First phase of memory management rewrite (see backend/utils/mmgr/README
authorTom Lane
Wed, 28 Jun 2000 03:33:33 +0000 (03:33 +0000)
committerTom Lane
Wed, 28 Jun 2000 03:33:33 +0000 (03:33 +0000)
for details).  It doesn't really do that much yet, since there are no
short-term memory contexts in the executor, but the infrastructure is
in place and long-term contexts are handled reasonably.  A few long-
standing bugs have been fixed, such as 'VACUUM; anything' in a single
query string crashing.  Also, out-of-memory is now considered a
recoverable ERROR, not FATAL.
Eliminate a large amount of crufty, now-dead code in and around
memory management.
Fix problem with holding off SIGTRAP, SIGSEGV, etc in postmaster and
backend startup.

74 files changed:
doc/src/sgml/geqo.sgml
doc/src/sgml/ref/declare.sgml
src/backend/Makefile
src/backend/access/heap/heapam.c
src/backend/access/transam/xact.c
src/backend/bootstrap/bootstrap.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/pg_proc.c
src/backend/commands/command.c
src/backend/commands/indexcmds.c
src/backend/commands/trigger.c
src/backend/commands/user.c
src/backend/commands/vacuum.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeHash.c
src/backend/executor/spi.c
src/backend/lib/Makefile
src/backend/lib/fstack.c [deleted file]
src/backend/lib/stringinfo.c
src/backend/libpq/be-fsstubs.c
src/backend/libpq/be-pqexec.c
src/backend/libpq/pqsignal.c
src/backend/optimizer/geqo/geqo_eval.c
src/backend/optimizer/geqo/geqo_main.c
src/backend/postmaster/postmaster.c
src/backend/rewrite/rewriteDefine.c
src/backend/rewrite/rewriteSupport.c
src/backend/storage/ipc/shmem.c
src/backend/storage/large_object/inv_api.c
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/proc.c
src/backend/storage/smgr/md.c
src/backend/tcop/postgres.c
src/backend/tcop/pquery.c
src/backend/utils/cache/catcache.c
src/backend/utils/cache/relcache.c
src/backend/utils/cache/temprel.c
src/backend/utils/error/elog.c
src/backend/utils/fmgr/dfmgr.c
src/backend/utils/hash/dynahash.c
src/backend/utils/init/Makefile
src/backend/utils/init/enbl.c [deleted file]
src/backend/utils/init/postinit.c
src/backend/utils/mb/conv.c
src/backend/utils/mmgr/Makefile
src/backend/utils/mmgr/README [new file with mode: 0644]
src/backend/utils/mmgr/aset.c
src/backend/utils/mmgr/mcxt.c
src/backend/utils/mmgr/oset.c [deleted file]
src/backend/utils/mmgr/palloc.c [deleted file]
src/backend/utils/mmgr/portalmem.c
src/include/commands/command.h
src/include/executor/hashjoin.h
src/include/executor/spi.h
src/include/executor/spi_priv.h
src/include/lib/fstack.h [deleted file]
src/include/libpq/pqsignal.h
src/include/miscadmin.h
src/include/nodes/memnodes.h
src/include/nodes/nodes.h
src/include/optimizer/geqo.h
src/include/postgres.h
src/include/storage/shmem.h
src/include/tcop/pquery.h
src/include/tcop/tcopprot.h
src/include/utils/catcache.h
src/include/utils/hsearch.h
src/include/utils/mcxt.h [deleted file]
src/include/utils/memutils.h
src/include/utils/module.h [deleted file]
src/include/utils/palloc.h
src/include/utils/portal.h

index fd6d58aca08228e19a6fb4a519de359130b66a0f..4f2f80e97a2a1fdd678fe60a05b092a97de0b72e 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer
 
 Basic Improvements
 
-
-Improve freeing of memory when query is already processed
-
-
-With large join queries the computing time spent for the genetic query
-optimization seems to be a mere fraction of the time
Postgres
-needs for freeing memory via routine MemoryContextFree,
-file backend/utils/mmgr/mcxt.c.
-Debugging showed that it get stucked in a loop of routine
-OrderedElemPop, file backend/utils/mmgr/oset.c.
-The same problems arise with long queries when using the normal
-Postgres query optimization algorithm.
-
-
-
 
 Improve genetic algorithm parameter settings
 
index c3c8b526807bb6eaeaa44dc950baf3f033210228..803949a1eaaf6447240d350267f211e822f6e129 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -153,12 +153,13 @@ SELECT
 
      
       
-NOTICE
-BlankPortalAssignName: portal "cursorname" already exists
+NOTICE:  Closing pre-existing portal "cursorname"
        
       
        
-   This error occurs if cursorname is already declared.
+   This message is reported if the same cursor name was already declared
+   in the current transaction block.  The previous definition is
+   discarded.
        
       
      
index 37a4a7bae9dfb4280e8756f7082d3b22ccb579fa..ab691cef462b76f2471af50b2149667d76639cd0 100644 (file)
@@ -34,7 +34,7 @@
 #
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.55 2000/06/17 00:09:34 petere Exp $
+#    $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.56 2000/06/28 03:30:57 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -237,8 +237,6 @@ install-headers: prebuildheaders $(SRCDIR)/include/config.h
           $(HEADERDIR)/utils/fmgroids.h
    $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \
           $(HEADERDIR)/utils/palloc.h
-   $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/mcxt.h \
-          $(HEADERDIR)/utils/mcxt.h
    $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/access/attnum.h \
           $(HEADERDIR)/access/attnum.h
    $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \
index aacef2a66a93aee46fb4c41712db57e0cd9968aa..7ca83587a4df81f999b084537b5f494fd5cdf50a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.71 2000/06/15 04:09:34 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.72 2000/06/28 03:31:04 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1230,10 +1230,7 @@ heap_insert(Relation relation, HeapTuple tup)
     * ----------------
     */
    if (!OidIsValid(tup->t_data->t_oid))
-   {
        tup->t_data->t_oid = newoid();
-       LastOidProcessed = tup->t_data->t_oid;
-   }
    else
        CheckMaxObjectId(tup->t_data->t_oid);
 
index d6551cc9c9cdd2d26b10ab79e680e61e5024944c..bc8f968571d54a7fd79446fad0d0a1916aafe541 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.67 2000/06/18 22:43:51 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.68 2000/06/28 03:31:05 tgl Exp $
  *
  * NOTES
  *     Transaction aborts can now occur two ways:
  *
  *     These two cases used to be treated identically, but now
  *     we need to distinguish them.  Why?  consider the following
- *     two situatuons:
+ *     two situations:
  *
  *             case 1                          case 2
  *             ------                          ------
  *     1) user types BEGIN             1) user types BEGIN
  *     2) user does something          2) user does something
  *     3) user does not like what      3) system aborts for some reason
- *        she shes and types ABORT
+ *        she sees and types ABORT
  *
  *     In case 1, we want to abort the transaction and return to the
  *     default state.  In case 2, there may be more commands coming
  *     * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
  *     * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
  *
+ *     Low-level transaction abort handling is divided into two phases:
+ *     * AbortTransaction() executes as soon as we realize the transaction
+ *       has failed.  It should release all shared resources (locks etc)
+ *       so that we do not delay other backends unnecessarily.
+ *     * CleanupTransaction() executes when we finally see a user COMMIT
+ *       or ROLLBACK command; it cleans things up and gets us out of
+ *       the transaction internally.  In particular, we mustn't destroy
+ *       TransactionCommandContext until this point.
+ *
  *  NOTES
  *     This file is an attempt at a redesign of the upper layer
  *     of the V1 transaction system which was too poorly thought
@@ -70,7 +79,7 @@
  *             StartTransaction
  *             CommitTransaction
  *             AbortTransaction
- *             UserAbortTransaction
+ *             CleanupTransaction
  *
  *     are provided to do the lower level work like recording
  *     the transaction status in the log and doing memory cleanup.
 #include "commands/async.h"
 #include "commands/sequence.h"
 #include "commands/trigger.h"
+#include "executor/spi.h"
 #include "libpq/be-fsstubs.h"
 #include "storage/proc.h"
 #include "storage/sinval.h"
-#include "utils/temprel.h"
 #include "utils/inval.h"
+#include "utils/memutils.h"
 #include "utils/portal.h"
 #include "utils/relcache.h"
+#include "utils/temprel.h"
 
 extern bool SharedBufferChanged;
 
@@ -165,6 +176,7 @@ static void AbortTransaction(void);
 static void AtAbort_Cache(void);
 static void AtAbort_Locks(void);
 static void AtAbort_Memory(void);
+static void AtCleanup_Memory(void);
 static void AtCommit_Cache(void);
 static void AtCommit_LocalCache(void);
 static void AtCommit_Locks(void);
@@ -172,6 +184,7 @@ static void AtCommit_Memory(void);
 static void AtStart_Cache(void);
 static void AtStart_Locks(void);
 static void AtStart_Memory(void);
+static void CleanupTransaction(void);
 static void CommitTransaction(void);
 static void RecordTransactionAbort(void);
 static void RecordTransactionCommit(void);
@@ -243,7 +256,7 @@ bool        AMI_OVERRIDE = false;
 
 /* --------------------------------
  *     TranactionFlushEnabled()
- *     SetTranactionFlushEnabled()
+ *     SetTransactionFlushEnabled()
  *
  *     These are used to test and set the "TransactionFlushState"
  *     varable.  If this variable is true (the default), then
@@ -580,22 +593,35 @@ AtStart_Locks()
 static void
 AtStart_Memory()
 {
-   Portal      portal;
-   MemoryContext portalContext;
+   /* ----------------
+    *  We shouldn't have any transaction contexts already.
+    * ----------------
+    */
+   Assert(TopTransactionContext == NULL);
+   Assert(TransactionCommandContext == NULL);
 
    /* ----------------
-    *  get the blank portal and its memory context
+    *  Create a toplevel context for the transaction.
     * ----------------
     */
-   portal = GetPortalByName(NULL);
-   portalContext = (MemoryContext) PortalGetHeapMemory(portal);
+   TopTransactionContext =
+       AllocSetContextCreate(TopMemoryContext,
+                             "TopTransactionContext",
+                             ALLOCSET_DEFAULT_MINSIZE,
+                             ALLOCSET_DEFAULT_INITSIZE,
+                             ALLOCSET_DEFAULT_MAXSIZE);
 
    /* ----------------
-    *  tell system to allocate in the blank portal context
+    *  Create a statement-level context and make it active.
     * ----------------
     */
-   MemoryContextSwitchTo(portalContext);
-   StartPortalAllocMode(DefaultAllocMode, 0);
+   TransactionCommandContext =
+       AllocSetContextCreate(TopTransactionContext,
+                             "TransactionCommandContext",
+                             ALLOCSET_DEFAULT_MINSIZE,
+                             ALLOCSET_DEFAULT_INITSIZE,
+                             ALLOCSET_DEFAULT_MAXSIZE);
+   MemoryContextSwitchTo(TransactionCommandContext);
 }
 
 
@@ -711,22 +737,21 @@ AtCommit_Locks()
 static void
 AtCommit_Memory()
 {
-   Portal      portal;
-
    /* ----------------
-    *  Release all heap memory in the blank portal.
+    *  Now that we're "out" of a transaction, have the
+    *  system allocate things in the top memory context instead
+    *  of per-transaction contexts.
     * ----------------
     */
-   portal = GetPortalByName(NULL);
-   PortalResetHeapMemory(portal);
+   MemoryContextSwitchTo(TopMemoryContext);
 
    /* ----------------
-    *  Now that we're "out" of a transaction, have the
-    *  system allocate things in the top memory context instead
-    *  of the blank portal memory context.
+    *  Release all transaction-local memory.
     * ----------------
     */
-   MemoryContextSwitchTo(TopMemoryContext);
+   MemoryContextDelete(TopTransactionContext);
+   TopTransactionContext = NULL;
+   TransactionCommandContext = NULL;
 }
 
 /* ----------------------------------------------------------------
@@ -798,24 +823,52 @@ AtAbort_Locks()
 static void
 AtAbort_Memory()
 {
-   Portal      portal;
+   /* ----------------
+    *  Make sure we are in a valid context (not a child of
+    *  TransactionCommandContext...)
+    * ----------------
+    */
+   MemoryContextSwitchTo(TransactionCommandContext);
 
    /* ----------------
-    *  Release all heap memory in the blank portal.
+    *  We do not want to destroy transaction contexts yet,
+    *  but it should be OK to delete any command-local memory.
     * ----------------
     */
-   portal = GetPortalByName(NULL);
-   PortalResetHeapMemory(portal);
+   MemoryContextResetAndDeleteChildren(TransactionCommandContext);
+}
+
+
+/* ----------------------------------------------------------------
+ *                     CleanupTransaction stuff
+ * ----------------------------------------------------------------
+ */
 
+/* --------------------------------
+ *     AtCleanup_Memory
+ * --------------------------------
+ */
+static void
+AtCleanup_Memory()
+{
    /* ----------------
     *  Now that we're "out" of a transaction, have the
     *  system allocate things in the top memory context instead
-    *  of the blank portal memory context.
+    *  of per-transaction contexts.
     * ----------------
     */
    MemoryContextSwitchTo(TopMemoryContext);
+
+   /* ----------------
+    *  Release all transaction-local memory.
+    * ----------------
+    */
+   MemoryContextDelete(TopTransactionContext);
+   TopTransactionContext = NULL;
+   TransactionCommandContext = NULL;
 }
 
+
 /* ----------------------------------------------------------------
  *                     interface routines
  * ----------------------------------------------------------------
@@ -854,6 +907,7 @@ StartTransaction()
    s->state = TRANS_START;
 
    SetReindexProcessing(false);
+
    /* ----------------
     *  generate a new transaction id
     * ----------------
@@ -874,9 +928,9 @@ StartTransaction()
     *  initialize the various transaction subsystems
     * ----------------
     */
+   AtStart_Memory();
    AtStart_Cache();
    AtStart_Locks();
-   AtStart_Memory();
 
    /* ----------------
     *  Tell the trigger manager to we're starting a transaction
@@ -974,20 +1028,21 @@ CommitTransaction()
    }
 
    RelationPurgeLocalRelation(true);
+   AtEOXact_SPI();
    AtEOXact_nbtree();
    AtCommit_Cache();
    AtCommit_Locks();
    AtCommit_Memory();
    AtEOXact_Files();
 
+   SharedBufferChanged = false; /* safest place to do it */
+
    /* ----------------
     *  done with commit processing, set current transaction
     *  state back to default
     * ----------------
     */
    s->state = TRANS_DEFAULT;
-   SharedBufferChanged = false;/* safest place to do it */
-
 }
 
 /* --------------------------------
@@ -1018,7 +1073,7 @@ AbortTransaction()
        return;
 
    if (s->state != TRANS_INPROGRESS)
-       elog(NOTICE, "AbortTransaction and not in in-progress state ");
+       elog(NOTICE, "AbortTransaction and not in in-progress state");
 
    /* ----------------
     *  Tell the trigger manager that this transaction is about to be
@@ -1043,24 +1098,56 @@ AbortTransaction()
    AtAbort_Notify();
    CloseSequences();
    AtEOXact_portals();
-   if (CommonSpecialPortalIsOpen())
-       CommonSpecialPortalClose();
    RecordTransactionAbort();
    RelationPurgeLocalRelation(false);
    invalidate_temp_relations();
+   AtEOXact_SPI();
    AtEOXact_nbtree();
    AtAbort_Cache();
    AtAbort_Locks();
    AtAbort_Memory();
    AtEOXact_Files();
 
+   SharedBufferChanged = false; /* safest place to do it */
+
+   /* ----------------
+    *  State remains TRANS_ABORT until CleanupTransaction().
+    * ----------------
+    */
+}
+
+/* --------------------------------
+ *     CleanupTransaction
+ *
+ * --------------------------------
+ */
+static void
+CleanupTransaction()
+{
+   TransactionState s = CurrentTransactionState;
+
+   if (s->state == TRANS_DISABLED)
+       return;
+
+   /* ----------------
+    *  State should still be TRANS_ABORT from AbortTransaction().
+    * ----------------
+    */
+   if (s->state != TRANS_ABORT)
+       elog(FATAL, "CleanupTransaction and not in abort state");
+
+   /* ----------------
+    *  do abort cleanup processing
+    * ----------------
+    */
+   AtCleanup_Memory();
+
    /* ----------------
     *  done with abort processing, set current transaction
     *  state back to default
     * ----------------
     */
    s->state = TRANS_DEFAULT;
-   SharedBufferChanged = false;/* safest place to do it */
 }
 
 /* --------------------------------
@@ -1133,7 +1220,7 @@ StartTransactionCommand()
            /* ----------------
             *      This means we somehow aborted and the last call to
             *      CommitTransactionCommand() didn't clear the state so
-            *      we remain in the ENDABORT state and mabey next time
+            *      we remain in the ENDABORT state and maybe next time
             *      we get to CommitTransactionCommand() the state will
             *      get reset to default.
             * ----------------
@@ -1142,6 +1229,13 @@ StartTransactionCommand()
            elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
            break;
    }
+
+   /*
+    * We must switch to TransactionCommandContext before returning.
+    * This is already done if we called StartTransaction, otherwise not.
+    */
+   Assert(TransactionCommandContext != NULL);
+   MemoryContextSwitchTo(TransactionCommandContext);
 }
 
 /* --------------------------------
@@ -1181,28 +1275,25 @@ CommitTransactionCommand()
             *      command counter and return.  Someday we may free resources
             *      local to the command.
             *
-            *      That someday is today, at least for memory allocated by
-            *      command in the BlankPortal' HeapMemory context.
+            *      That someday is today, at least for memory allocated in
+            *      TransactionCommandContext.
             *              - vadim 03/25/97
             * ----------------
             */
        case TBLOCK_INPROGRESS:
            CommandCounterIncrement();
-#ifdef TBL_FREE_CMD_MEMORY
-           EndPortalAllocMode();
-           StartPortalAllocMode(DefaultAllocMode, 0);
-#endif
+           MemoryContextResetAndDeleteChildren(TransactionCommandContext);
            break;
 
            /* ----------------
             *      This is the case when we just got the "END TRANSACTION"
-            *      statement, so we go back to the default state and
-            *      commit the transaction.
+            *      statement, so we commit the transaction and go back to
+            *      the default state.
             * ----------------
             */
        case TBLOCK_END:
-           s->blockState = TBLOCK_DEFAULT;
            CommitTransaction();
+           s->blockState = TBLOCK_DEFAULT;
            break;
 
            /* ----------------
@@ -1218,10 +1309,11 @@ CommitTransactionCommand()
            /* ----------------
             *      Here we were in an aborted transaction block which
             *      just processed the "END TRANSACTION" command from the
-            *      user, so now we return the to default state.
+            *      user, so clean up and return to the default state.
             * ----------------
             */
        case TBLOCK_ENDABORT:
+           CleanupTransaction();
            s->blockState = TBLOCK_DEFAULT;
            break;
    }
@@ -1240,11 +1332,12 @@ AbortCurrentTransaction()
    {
            /* ----------------
             *      if we aren't in a transaction block, we
-            *      just do our usual abort transaction.
+            *      just do the basic abort & cleanup transaction.
             * ----------------
             */
        case TBLOCK_DEFAULT:
            AbortTransaction();
+           CleanupTransaction();
            break;
 
            /* ----------------
@@ -1257,6 +1350,7 @@ AbortCurrentTransaction()
        case TBLOCK_BEGIN:
            s->blockState = TBLOCK_ABORT;
            AbortTransaction();
+           /* CleanupTransaction happens when we exit TBLOCK_ABORT */
            break;
 
            /* ----------------
@@ -1269,6 +1363,7 @@ AbortCurrentTransaction()
        case TBLOCK_INPROGRESS:
            s->blockState = TBLOCK_ABORT;
            AbortTransaction();
+           /* CleanupTransaction happens when we exit TBLOCK_ABORT */
            break;
 
            /* ----------------
@@ -1281,6 +1376,7 @@ AbortCurrentTransaction()
        case TBLOCK_END:
            s->blockState = TBLOCK_DEFAULT;
            AbortTransaction();
+           CleanupTransaction();
            break;
 
            /* ----------------
@@ -1297,10 +1393,11 @@ AbortCurrentTransaction()
             *      Here we were in an aborted transaction block which
             *      just processed the "END TRANSACTION" command but somehow
             *      aborted again.. since we must have done the abort
-            *      processing, we return to the default state.
+            *      processing, we clean up and return to the default state.
             * ----------------
             */
        case TBLOCK_ENDABORT:
+           CleanupTransaction();
            s->blockState = TBLOCK_DEFAULT;
            break;
    }
@@ -1394,13 +1491,14 @@ EndTransactionBlock(void)
    }
 
    /* ----------------
-    *  We should not get here, but if we do, we go to the ENDABORT
-    *  state after printing a warning.  The upcoming call to
+    *  here, the user issued COMMIT when not inside a transaction.
+    *  Issue a notice and go to abort state.  The upcoming call to
     *  CommitTransactionCommand() will then put us back into the
     *  default state.
     * ----------------
     */
    elog(NOTICE, "COMMIT: no transaction in progress");
+   AbortTransaction();
    s->blockState = TBLOCK_ENDABORT;
 }
 
@@ -1427,29 +1525,23 @@ AbortTransactionBlock(void)
         *  here we were inside a transaction block something
         *  screwed up inside the system so we enter the abort state,
         *  do the abort processing and then return.
-        *  We remain in the abort state until we see the upcoming
+        *  We remain in the abort state until we see an
         *  END TRANSACTION command.
         * ----------------
         */
        s->blockState = TBLOCK_ABORT;
-
-       /* ----------------
-        *  do abort processing and return
-        * ----------------
-        */
        AbortTransaction();
        return;
    }
 
    /* ----------------
-    *  this case should not be possible, because it would mean
-    *  the user entered an "abort" from outside a transaction block.
-    *  So we print an error message, abort the transaction and
-    *  enter the "ENDABORT" state so we will end up in the default
-    *  state after the upcoming CommitTransactionCommand().
+    *  here, the user issued ABORT when not inside a transaction.
+    *  Issue a notice and go to abort state.  The upcoming call to
+    *  CommitTransactionCommand() will then put us back into the
+    *  default state.
     * ----------------
     */
-   elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
+   elog(NOTICE, "ROLLBACK: no transaction in progress");
    AbortTransaction();
    s->blockState = TBLOCK_ENDABORT;
 }
@@ -1495,27 +1587,16 @@ UserAbortTransactionBlock()
         * ----------------
         */
        s->blockState = TBLOCK_ABORT;
-
-       /* ----------------
-        *  do abort processing
-        * ----------------
-        */
        AbortTransaction();
-
-       /* ----------------
-        *  change to the end abort state and return
-        * ----------------
-        */
        s->blockState = TBLOCK_ENDABORT;
        return;
    }
 
    /* ----------------
-    *  this case should not be possible, because it would mean
-    *  the user entered a "rollback" from outside a transaction block.
-    *  So we print an error message, abort the transaction and
-    *  enter the "ENDABORT" state so we will end up in the default
-    *  state after the upcoming CommitTransactionCommand().
+    *  here, the user issued ABORT when not inside a transaction.
+    *  Issue a notice and go to abort state.  The upcoming call to
+    *  CommitTransactionCommand() will then put us back into the
+    *  default state.
     * ----------------
     */
    elog(NOTICE, "ROLLBACK: no transaction in progress");
@@ -1540,7 +1621,10 @@ AbortOutOfAnyTransaction()
     * Get out of any low-level transaction
     */
    if (s->state != TRANS_DEFAULT)
+   {
        AbortTransaction();
+       CleanupTransaction();
+   }
 
    /*
     * Now reset the high-level state
index b49d5ef8bf35d33c6f2450cca25099cebca56b8d..54d4ab8139c17802b627b903b5d234ca9131e8a7 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.87 2000/06/22 22:31:17 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.88 2000/06/28 03:31:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "miscadmin.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
+#include "utils/exc.h"
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
-#include "utils/portal.h"
+
 
 #define ALLOC(t, c)        ((t *) calloc((unsigned)(c), sizeof(t)))
 
-extern void BaseInit(void);
 extern void StartupXLOG(void);
 extern void ShutdownXLOG(void);
 extern void BootStrapXLOG(void);
@@ -144,8 +144,8 @@ static Datum values[MAXATTR];   /* corresponding attribute values */
 int            numattr;            /* number of attributes for cur. rel */
 
 int            DebugMode;
-static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
-                                                * context */
+
+static MemoryContext nogc = NULL; /* special no-gc mem context */
 
 extern int optind;
 extern char *optarg;
@@ -240,6 +240,17 @@ BootstrapMain(int argc, char *argv[])
 
    MyProcPid = getpid();
 
+   /*
+    * Fire up essential subsystems: error and memory management
+    *
+    * If we are running under the postmaster, this is done already.
+    */
+   if (!IsUnderPostmaster)
+   {
+       EnableExceptionHandling(true);
+       MemoryContextInit();
+   }
+
    /* ----------------
     *  process command arguments
     * ----------------
@@ -428,7 +439,6 @@ boot_openrel(char *relname)
 
    if (Typ == (struct typmap **) NULL)
    {
-       StartPortalAllocMode(DefaultAllocMode, 0);
        rel = heap_openr(TypeRelationName, NoLock);
        Assert(rel);
        scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
@@ -445,13 +455,13 @@ boot_openrel(char *relname)
        while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
        {
            (*app)->am_oid = tup->t_data->t_oid;
-           memmove((char *) &(*app++)->am_typ,
-                   (char *) GETSTRUCT(tup),
-                   sizeof((*app)->am_typ));
+           memcpy((char *) &(*app)->am_typ,
+                  (char *) GETSTRUCT(tup),
+                  sizeof((*app)->am_typ));
+           app++;
        }
        heap_endscan(scan);
        heap_close(rel, NoLock);
-       EndPortalAllocMode();
    }
 
    if (reldesc != NULL)
@@ -1088,10 +1098,14 @@ index_register(char *heap,
     * them later.
     */
 
-   if (nogc == (GlobalMemory) NULL)
-       nogc = CreateGlobalMemory("BootstrapNoGC");
+   if (nogc == NULL)
+       nogc = AllocSetContextCreate((MemoryContext) NULL,
+                                    "BootstrapNoGC",
+                                    ALLOCSET_DEFAULT_MINSIZE,
+                                    ALLOCSET_DEFAULT_INITSIZE,
+                                    ALLOCSET_DEFAULT_MAXSIZE);
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
+   oldcxt = MemoryContextSwitchTo(nogc);
 
    newind = (IndexList *) palloc(sizeof(IndexList));
    newind->il_heap = pstrdup(heap);
index 7aeec8adb085c21c3a55a55def274c38b39d3a4a..9ba935f716d02e975d927289de14e1b74d097fda 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.133 2000/06/18 22:43:55 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.134 2000/06/28 03:31:22 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -188,38 +188,27 @@ heap_create(char *relname,
             relname);
    }
 
-   /* ----------------
-    *  switch to the cache context so that we don't lose
-    *  allocations at the end of this transaction, I guess.
-    *  -cim 6/14/90
-    * ----------------
-    */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
-
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
-
    /* ----------------
     *  real ugly stuff to assign the proper relid in the relation
     *  descriptor follows.
     * ----------------
     */
-   if (relname && !strcmp(RelationRelationName, relname))
+   if (relname && strcmp(RelationRelationName, relname) == 0)
    {
        relid = RelOid_pg_class;
        nailme = true;
    }
-   else if (relname && !strcmp(AttributeRelationName, relname))
+   else if (relname && strcmp(AttributeRelationName, relname) == 0)
    {
        relid = RelOid_pg_attribute;
        nailme = true;
    }
-   else if (relname && !strcmp(ProcedureRelationName, relname))
+   else if (relname && strcmp(ProcedureRelationName, relname) == 0)
    {
        relid = RelOid_pg_proc;
        nailme = true;
    }
-   else if (relname && !strcmp(TypeRelationName, relname))
+   else if (relname && strcmp(TypeRelationName, relname) == 0)
    {
        relid = RelOid_pg_type;
        nailme = true;
@@ -234,6 +223,15 @@ heap_create(char *relname,
                 (int) MyProcPid, uniqueId++);
    }
 
+   /* ----------------
+    *  switch to the cache context to create the relcache entry.
+    * ----------------
+    */
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
+
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+
    /* ----------------
     *  allocate a new relation descriptor.
     * ----------------
@@ -287,6 +285,8 @@ heap_create(char *relname,
 
    /* ----------------
     *  have the storage manager create the relation.
+    *
+    * XXX shouldn't we switch out of CacheMemoryContext for that?
     * ----------------
     */
 
index 5b8e005c5f646bd3ec08d9d2de57158ec437249d..c73761899682d8d977fc2ebcb283bece1295cfe7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.119 2000/06/18 22:43:55 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.120 2000/06/28 03:31:23 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -442,10 +442,10 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
     *    context changes
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
 
@@ -904,16 +904,16 @@ InitIndexStrategy(int numatts,
     *  it will be lost at the end of the transaction.
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
 
-   strategy = (IndexStrategy)
-       MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
+   strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
+                                                 strsize);
 
    if (amsupport > 0)
    {
        strsize = numatts * (amsupport * sizeof(RegProcedure));
-       support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
+       support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
                                                      strsize);
    }
    else
index 836790c82a6feb3a3b531ed338ffd742b20dcd0e..e6091f6f63c749cb5dd64a79ab85f492ffc3effc 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.44 2000/06/14 04:53:44 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.45 2000/06/28 03:31:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -217,8 +217,7 @@ ProcedureCreate(char *procedureName,
 
    if (languageObjectId == SQLlanguageId)
    {
-       querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount,
-                                             FALSE);
+       querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount);
        /* typecheck return value */
        pg_checkretval(typeObjectId, querytree_list);
    }
index 5644afc46c1018ce2c2fd7c067d412bbd189908d..d0bd89fdfd2efbb67c041dfe7bcd9c243555c62b 100644 (file)
@@ -8,13 +8,9 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.80 2000/06/15 04:09:45 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.81 2000/06/28 03:31:28 tgl Exp $
  *
  * NOTES
- *   The PortalExecutorHeapMemory crap needs to be eliminated
- *   by designing a better executor / portal processing memory
- *   interface.
- *
  *   The PerformAddAttribute() code, like most of the relation
  *   manipulating code in the commands/ directory, should go
  *   someplace closer to the lib/catalog code.
 #include "parser/parse.h"
 #endif  /* _DROP_COLUMN_HACK__ */
 
-/* ----------------
- *     PortalExecutorHeapMemory stuff
- *
- *     This is where the XXXSuperDuperHacky code was. -cim 3/15/90
- * ----------------
- */
-MemoryContext PortalExecutorHeapMemory = NULL;
 
 /* --------------------------------
  *     PortalCleanup
@@ -55,7 +44,7 @@ MemoryContext PortalExecutorHeapMemory = NULL;
 void
 PortalCleanup(Portal portal)
 {
-   MemoryContext context;
+   MemoryContext oldcontext;
 
    /* ----------------
     *  sanity checks
@@ -68,8 +57,7 @@ PortalCleanup(Portal portal)
     *  set proper portal-executor context before calling ExecMain.
     * ----------------
     */
-   context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
-   PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
+   oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
    /* ----------------
     *  tell the executor to shutdown the query
@@ -81,8 +69,7 @@ PortalCleanup(Portal portal)
     *  switch back to previous context
     * ----------------
     */
-   MemoryContextSwitchTo(context);
-   PortalExecutorHeapMemory = (MemoryContext) NULL;
+   MemoryContextSwitchTo(oldcontext);
 }
 
 /* --------------------------------
@@ -99,7 +86,7 @@ PerformPortalFetch(char *name,
    Portal      portal;
    int         feature;
    QueryDesc  *queryDesc;
-   MemoryContext context;
+   MemoryContext oldcontext;
    Const       limcount;
 
    /* ----------------
@@ -108,7 +95,7 @@ PerformPortalFetch(char *name,
     */
    if (name == NULL)
    {
-       elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
+       elog(NOTICE, "PerformPortalFetch: missing portal name");
        return;
    }
 
@@ -120,12 +107,11 @@ PerformPortalFetch(char *name,
    limcount.type = T_Const;
    limcount.consttype = INT4OID;
    limcount.constlen = sizeof(int4);
-   limcount.constvalue = (Datum) count;
-   limcount.constisnull = FALSE;
-   limcount.constbyval = TRUE;
-   limcount.constisset = FALSE;
-   limcount.constiscast = FALSE;
-
+   limcount.constvalue = Int32GetDatum(count);
+   limcount.constisnull = false;
+   limcount.constbyval = true;
+   limcount.constisset = false;
+   limcount.constiscast = false;
 
    /* ----------------
     *  get the portal from the portal name
@@ -143,9 +129,7 @@ PerformPortalFetch(char *name,
     *  switch into the portal context
     * ----------------
     */
-   context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
-
-   AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
+   oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
    /* ----------------
     *  setup "feature" to tell the executor what direction and
@@ -174,8 +158,7 @@ PerformPortalFetch(char *name,
 
    BeginCommand(name,
                 queryDesc->operation,
-                portal->attinfo,       /* QueryDescGetTypeInfo(queryDesc),
-                                        * */
+                portal->attinfo, /* QueryDescGetTypeInfo(queryDesc) */
                 false,         /* portal fetches don't end up in
                                 * relations */
                 false,         /* this is a portal fetch, not a "retrieve
@@ -187,27 +170,23 @@ PerformPortalFetch(char *name,
     *  execute the portal fetch operation
     * ----------------
     */
-   PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
-
    ExecutorRun(queryDesc, PortalGetState(portal), feature,
                (Node *) NULL, (Node *) &limcount);
 
    if (dest == None)           /* MOVE */
        pfree(queryDesc);
 
+   /* ----------------
+    * Switch back to old context.
+    * ----------------
+    */
+   MemoryContextSwitchTo(oldcontext);
+
    /* ----------------
     * Note: the "end-of-command" tag is returned by higher-level
     *       utility code
-    *
-    * Return blank portal for now.
-    * Otherwise, this named portal will be cleaned.
-    * Note: portals will only be supported within a BEGIN...END
-    * block in the near future.  Later, someone will fix it to
-    * do what is possible across transaction boundries.
     * ----------------
     */
-   MemoryContextSwitchTo(
-            (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
 }
 
 /* --------------------------------
@@ -225,15 +204,10 @@ PerformPortalClose(char *name, CommandDest dest)
     */
    if (name == NULL)
    {
-       elog(NOTICE, "PerformPortalClose: blank portal unsupported");
+       elog(NOTICE, "PerformPortalClose: missing portal name");
        return;
    }
 
-   if (PortalNameIsSpecial(name))
-       elog(ERROR,
-            "The portal name \"%s\" is reserved for internal use",
-            name);
-
    /* ----------------
     *  get the portal from the portal name
     * ----------------
index e5896b304c7404a39b171948fab7d81a29e9c868..bb45f01f6733da82eef7efc199e21ef03d08a1ce 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.31 2000/06/17 23:41:36 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.32 2000/06/28 03:31:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,6 @@
 #include "utils/fmgroids.h"
 #include "utils/syscache.h"
 #include "miscadmin.h"         /* ReindexDatabase() */
-#include "utils/portal.h"      /* ReindexDatabase() */
 #include "catalog/catalog.h"   /* ReindexDatabase() */
 
 #define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
@@ -764,7 +763,6 @@ ReindexTable(const char *name, bool force)
  *     "ERROR" if table nonexistent.
  *     ...
  */
-extern Oid MyDatabaseId;
 void
 ReindexDatabase(const char *dbname, bool force, bool all)
 {
@@ -780,7 +778,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
    Oid         db_id;
    char       *username;
    ScanKeyData scankey;
-   PortalVariableMemory pmem;
+   MemoryContext private_context;
    MemoryContext old;
    int         relcnt,
                relalc,
@@ -808,16 +806,34 @@ ReindexDatabase(const char *dbname, bool force, bool all)
    db_id = dbtuple->t_data->t_oid;
    db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
    heap_endscan(scan);
+   heap_close(relation, NoLock);
+
    if (user_id != db_owner && !superuser)
        elog(ERROR, "REINDEX DATABASE: Permission denied.");
 
    if (db_id != MyDatabaseId)
        elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
 
-   heap_close(relation, NoLock);
+   /*
+    * We cannot run inside a user transaction block; if we were
+    * inside a transaction, then our commit- and
+    * start-transaction-command calls would not have the intended effect!
+    */
+   if (IsTransactionBlock())
+       elog(ERROR, "REINDEX DATABASE cannot run inside a BEGIN/END block");
+
+   /*
+    * Create a memory context that will survive forced transaction commits
+    * we do below.  Since it is a child of QueryContext, it will go away
+    * eventually even if we suffer an error; there's no need for special
+    * abort cleanup logic.
+    */
+   private_context = AllocSetContextCreate(QueryContext,
+                                           "ReindexDatabase",
+                                           ALLOCSET_DEFAULT_MINSIZE,
+                                           ALLOCSET_DEFAULT_INITSIZE,
+                                           ALLOCSET_DEFAULT_MAXSIZE);
 
-   CommonSpecialPortalOpen();
-   pmem = CommonSpecialPortalGetMemory();
    relationRelation = heap_openr(RelationRelationName, AccessShareLock);
    scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL);
    relcnt = relalc = 0;
@@ -832,7 +848,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
        }
        if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
        {
-           old = MemoryContextSwitchTo((MemoryContext) pmem);
+           old = MemoryContextSwitchTo(private_context);
            if (relcnt == 0)
            {
                relalc = oncealc;
@@ -859,6 +875,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
            elog(NOTICE, "relation %d was reindexed", relids[i]);
        CommitTransactionCommand();
    }
-   CommonSpecialPortalClose();
    StartTransactionCommand();
+
+   MemoryContextDelete(private_context);
 }
index 62d88caf393c0225574ae22bccfe2c83fb8287a1..fbb5a694b88572763c9176bb8c394f3fa47b8269 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.69 2000/06/08 22:37:01 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.70 2000/06/28 03:31:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1029,8 +1029,8 @@ ltrmark:;
  * end.
  * ----------
  */
-static GlobalMemory deftrig_gcxt = NULL;
-static GlobalMemory deftrig_cxt = NULL;
+static MemoryContext deftrig_gcxt = NULL;
+static MemoryContext deftrig_cxt = NULL;
 
 /* ----------
  * Global data that tells which triggers are actually in
@@ -1104,7 +1104,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
     * as the current and return that.
     * ----------
     */
-   oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+   oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
    trigstate = (DeferredTriggerStatus)
        palloc(sizeof(DeferredTriggerStatusData));
@@ -1366,7 +1366,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
 int
 DeferredTriggerInit(void)
 {
-   deftrig_gcxt = CreateGlobalMemory("DeferredTriggerSession");
+   deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
+                                        "DeferredTriggerSession",
+                                        ALLOCSET_DEFAULT_MINSIZE,
+                                        ALLOCSET_DEFAULT_INITSIZE,
+                                        ALLOCSET_DEFAULT_MAXSIZE);
+
    return 0;
 }
 
@@ -1395,8 +1400,12 @@ DeferredTriggerBeginXact(void)
     * from the per session context to here.
     * ----------
     */
-   deftrig_cxt = CreateGlobalMemory("DeferredTriggerXact");
-   oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+   deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
+                                       "DeferredTriggerXact",
+                                       ALLOCSET_DEFAULT_MINSIZE,
+                                       ALLOCSET_DEFAULT_INITSIZE,
+                                       ALLOCSET_DEFAULT_MAXSIZE);
+   oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
    deftrig_all_isset = deftrig_dfl_all_isset;
    deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
@@ -1461,7 +1470,7 @@ DeferredTriggerEndXact(void)
 
    deferredTriggerInvokeEvents(false);
 
-   GlobalMemoryDestroy(deftrig_cxt);
+   MemoryContextDelete(deftrig_cxt);
    deftrig_cxt = NULL;
 }
 
@@ -1484,7 +1493,7 @@ DeferredTriggerAbortXact(void)
    if (deftrig_cxt == NULL)
        return;
 
-   GlobalMemoryDestroy(deftrig_cxt);
+   MemoryContextDelete(deftrig_cxt);
    deftrig_cxt = NULL;
 }
 
@@ -1521,7 +1530,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
             * ... outside of a transaction block
             * ----------
             */
-           oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
+           oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
 
            /* ----------
             * Drop all information about individual trigger states per
@@ -1555,7 +1564,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
             * ... inside of a transaction block
             * ----------
             */
-           oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+           oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
            /* ----------
             * Drop all information about individual trigger states per
@@ -1701,7 +1710,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
         * states of individual triggers on session level.
         * ----------
         */
-       oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
+       oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
 
        foreach(l, loid)
        {
@@ -1739,7 +1748,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
         * states of individual triggers on transaction level.
         * ----------
         */
-       oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+       oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
        foreach(l, loid)
        {
@@ -1827,7 +1836,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
     * Create a new event
     * ----------
     */
-   oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+   oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
    ntriggers = rel->trigdesc->n_after_row[event];
    triggers = rel->trigdesc->tg_after_row[event];
@@ -2022,7 +2031,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
     * Anything's fine up to here. Add the new event to the queue.
     * ----------
     */
-   oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+   oldcxt = MemoryContextSwitchTo(deftrig_cxt);
    deferredTriggerAddEvent(new_event);
    MemoryContextSwitchTo(oldcxt);
 
index 859cb31edad792304905cbaf1d96797225e8cd3d..9bb36311cc8d74d4023aff8635ceafac69eb5000 100644 (file)
@@ -1,12 +1,12 @@
 /*-------------------------------------------------------------------------
  *
  * user.c
- *   use pg_exec_query to create a new user in the catalog
+ *   Commands for manipulating users and groups.
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.61 2000/06/25 14:24:59 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.62 2000/06/28 03:31:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
index 5eed27387a72d220b530c6ef34a231a125ecd8ac..01ed68b3b717b20b741b2933050a90e64d5c0a0a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.161 2000/06/28 03:31:28 tgl Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -35,7 +35,6 @@
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/inval.h"
-#include "utils/portal.h"
 #include "utils/relcache.h"
 #include "utils/syscache.h"
 #include "utils/temprel.h"
@@ -48,9 +47,7 @@
 #endif
 
 
-bool       CommonSpecialPortalInUse = false;
-
-static Portal vac_portal;
+static MemoryContext vac_context = NULL;
 
 static int MESSAGE_LEVEL;      /* message level */
 
@@ -82,14 +79,13 @@ static int  vac_cmp_offno(const void *left, const void *right);
 static int vac_cmp_vtlinks(const void *left, const void *right);
 static bool enough_space(VacPage vacpage, Size len);
 static char *show_rusage(struct rusage * ru0);
-/* CommonSpecialPortal function at the bottom */
+
 
 void
 vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
 {
    NameData    VacRel;
    Name        VacRelName;
-   PortalVariableMemory pmem;
    MemoryContext old;
    List       *le;
    List       *anal_cols2 = NIL;
@@ -114,8 +110,18 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
    else
        MESSAGE_LEVEL = DEBUG;
 
-   /* Create special portal for cross-transaction storage */
-   CommonSpecialPortalOpen();
+   /*
+    * Create special memory context for cross-transaction storage.
+    *
+    * Since it is a child of QueryContext, it will go away eventually
+    * even if we suffer an error; there's no need for special abort
+    * cleanup logic.
+    */
+   vac_context = AllocSetContextCreate(QueryContext,
+                                       "Vacuum",
+                                       ALLOCSET_DEFAULT_MINSIZE,
+                                       ALLOCSET_DEFAULT_INITSIZE,
+                                       ALLOCSET_DEFAULT_MAXSIZE);
 
    /* vacrel gets de-allocated on xact commit, so copy it to safe storage */
    if (vacrel)
@@ -127,8 +133,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
        VacRelName = NULL;
 
    /* must also copy the column list, if any, to safe storage */
-   pmem = CommonSpecialPortalGetMemory();
-   old = MemoryContextSwitchTo((MemoryContext) pmem);
+   old = MemoryContextSwitchTo(vac_context);
    foreach(le, anal_cols)
    {
        char       *col = (char *) lfirst(le);
@@ -198,11 +203,16 @@ vacuum_shutdown()
     */
    unlink(RELCACHE_INIT_FILENAME);
 
-   /* Clean up working storage */
-   CommonSpecialPortalClose();
-
    /* matches the CommitTransaction in PostgresMain() */
    StartTransactionCommand();
+
+   /*
+    * Clean up working storage --- note we must do this after
+    * StartTransactionCommand, else we might be trying to delete
+    * the active context!
+    */
+   MemoryContextDelete(vac_context);
+   vac_context = NULL;
 }
 
 /*
@@ -239,8 +249,6 @@ getrels(NameData *VacRelP)
    TupleDesc   tupdesc;
    HeapScanDesc scan;
    HeapTuple   tuple;
-   PortalVariableMemory portalmem;
-   MemoryContext old;
    VRelList    vrl,
                cur;
    Datum       d;
@@ -276,7 +284,6 @@ getrels(NameData *VacRelP)
                               F_CHAREQ, CharGetDatum('r'));
    }
 
-   portalmem = CommonSpecialPortalGetMemory();
    vrl = cur = (VRelList) NULL;
 
    rel = heap_openr(RelationRelationName, AccessShareLock);
@@ -302,25 +309,26 @@ getrels(NameData *VacRelP)
        }
 
        /* get a relation list entry for this guy */
-       old = MemoryContextSwitchTo((MemoryContext) portalmem);
        if (vrl == (VRelList) NULL)
-           vrl = cur = (VRelList) palloc(sizeof(VRelListData));
+           vrl = cur = (VRelList)
+               MemoryContextAlloc(vac_context, sizeof(VRelListData));
        else
        {
-           cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
+           cur->vrl_next = (VRelList)
+               MemoryContextAlloc(vac_context, sizeof(VRelListData));
            cur = cur->vrl_next;
        }
-       MemoryContextSwitchTo(old);
 
        cur->vrl_relid = tuple->t_data->t_oid;
        cur->vrl_next = (VRelList) NULL;
    }
-   if (found == false)
-       elog(NOTICE, "Vacuum: table not found");
 
    heap_endscan(scan);
    heap_close(rel, AccessShareLock);
 
+   if (!found)
+       elog(NOTICE, "Vacuum: table not found");
+
    CommitTransactionCommand();
 
    return vrl;
@@ -2275,62 +2283,6 @@ vac_cmp_vtlinks(const void *left, const void *right)
 
 }
 
-/*
- * This routines handle a special cross-transaction portal.
- * However it is automatically closed in case of abort.
- */
-void
-CommonSpecialPortalOpen(void)
-{
-   char       *pname;
-
-
-   if (CommonSpecialPortalInUse)
-       elog(ERROR, "CommonSpecialPortal is in use");
-
-   /*
-    * Create a portal for safe memory across transactions. We need to
-    * palloc the name space for it because our hash function expects the
-    * name to be on a longword boundary.  CreatePortal copies the name to
-    * safe storage for us.
-    */
-   pname = pstrdup(VACPNAME);
-   vac_portal = CreatePortal(pname);
-   pfree(pname);
-
-   /*
-    * Set flag to indicate that vac_portal must be removed after an error.
-    * This global variable is checked in the transaction manager on xact
-    * abort, and the routine CommonSpecialPortalClose() is called if
-    * necessary.
-    */
-   CommonSpecialPortalInUse = true;
-}
-
-void
-CommonSpecialPortalClose(void)
-{
-   /* Clear flag first, to avoid recursion if PortalDrop elog's */
-   CommonSpecialPortalInUse = false;
-
-   /*
-    * Release our portal for cross-transaction memory.
-    */
-   PortalDrop(&vac_portal);
-}
-
-PortalVariableMemory
-CommonSpecialPortalGetMemory(void)
-{
-   return PortalGetVariableMemory(vac_portal);
-}
-
-bool
-CommonSpecialPortalIsOpen(void)
-{
-   return CommonSpecialPortalInUse;
-}
-
 
 static void
 get_indices(Relation relation, int *nindices, Relation **Irel)
index ee5fabf170887b09feef74d4263bb06d28d18b57..6d8d93a47f1235c78782b12f889fef9f70ef66ec 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.34 2000/05/28 17:55:55 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.35 2000/06/28 03:31:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,8 +87,8 @@ init_execution_state(FunctionCachePtr fcache)
    nextes = newes;
    preves = (execution_state *) NULL;
 
-   queryTree_list = pg_parse_and_rewrite(fcache->src, fcache->argOidVect,
-                                         nargs, FALSE);
+   queryTree_list = pg_parse_and_rewrite(fcache->src,
+                                         fcache->argOidVect, nargs);
 
    foreach(qtl_item, queryTree_list)
    {
index c9d6299f4933d4430b7d9d2b47c501473917ba93..0289cf45bd3b4ebff487abbf04a70c965279492a 100644 (file)
@@ -32,7 +32,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.67 2000/06/15 03:32:09 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.68 2000/06/28 03:31:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -265,7 +265,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
            else
                newVal = FunctionCallInvoke(&fcinfo);
            if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
-               pfree(peraggstate->value1);
+               pfree(DatumGetPointer(peraggstate->value1));
            peraggstate->value1 = newVal;
            peraggstate->value1IsNull = fcinfo.isnull;
        }
@@ -288,7 +288,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
        else
            newVal = FunctionCallInvoke(&fcinfo);
        if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
-           pfree(peraggstate->value2);
+           pfree(DatumGetPointer(peraggstate->value2));
        peraggstate->value2 = newVal;
        peraggstate->value2IsNull = fcinfo.isnull;
    }
@@ -424,12 +424,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
    if (OidIsValid(peraggstate->xfn1_oid) &&
        !peraggstate->value1IsNull &&
        !peraggstate->transtype1ByVal)
-       pfree(peraggstate->value1);
+       pfree(DatumGetPointer(peraggstate->value1));
 
    if (OidIsValid(peraggstate->xfn2_oid) &&
        !peraggstate->value2IsNull &&
        !peraggstate->transtype2ByVal)
-       pfree(peraggstate->value2);
+       pfree(DatumGetPointer(peraggstate->value2));
 }
 
 /* ---------------------------------------
index b662883803af4b16e68b8eb10a50e0a432b9fc92..34b0a269a5b2dd892ea75d6aaf2c8ffdfcc208c4 100644 (file)
@@ -7,14 +7,14 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- * $Id: nodeHash.c,v 1.47 2000/06/15 04:09:52 momjian Exp $
+ * $Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * INTERFACE ROUTINES
  *     ExecHash        - generate an in-memory hash table of the relation
- *     ExecInitHash    - initialize node and subnodes..
+ *     ExecInitHash    - initialize node and subnodes
  *     ExecEndHash     - shutdown node and subnodes
  *
  */
 #include 
 
 #include "postgres.h"
+
 #include "executor/execdebug.h"
 #include "executor/nodeHash.h"
 #include "executor/nodeHashjoin.h"
 #include "miscadmin.h"
-#include "utils/portal.h"
+
 
 static int hashFunc(Datum key, int len, bool byVal);
 
@@ -235,8 +236,6 @@ ExecHashTableCreate(Hash *node)
    int         totalbuckets;
    int         bucketsize;
    int         i;
-   Portal      myPortal;
-   char        myPortalName[64];
    MemoryContext oldcxt;
 
    /* ----------------
@@ -348,23 +347,21 @@ ExecHashTableCreate(Hash *node)
    hashtable->outerBatchSize = NULL;
 
    /* ----------------
-    *  Create a named portal in which to keep the hashtable working storage.
-    *  Each hashjoin must have its own portal, so be wary of name conflicts.
+    *  Create temporary memory contexts in which to keep the hashtable
+    *  working storage.  See notes in executor/hashjoin.h.
     * ----------------
     */
-   i = 0;
-   do
-   {
-       i++;
-       sprintf(myPortalName, "", i);
-       myPortal = GetPortalByName(myPortalName);
-   } while (PortalIsValid(myPortal));
-   myPortal = CreatePortal(myPortalName);
-   Assert(PortalIsValid(myPortal));
-   hashtable->myPortal = (void *) myPortal;    /* kluge for circular
-                                                * includes */
-   hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
-   hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
+   hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
+                                              "HashTableContext",
+                                              ALLOCSET_DEFAULT_MINSIZE,
+                                              ALLOCSET_DEFAULT_INITSIZE,
+                                              ALLOCSET_DEFAULT_MAXSIZE);
+
+   hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
+                                               "HashBatchContext",
+                                               ALLOCSET_DEFAULT_MINSIZE,
+                                               ALLOCSET_DEFAULT_INITSIZE,
+                                               ALLOCSET_DEFAULT_MAXSIZE);
 
    /* Allocate data that will live for the life of the hashjoin */
 
@@ -395,11 +392,10 @@ ExecHashTableCreate(Hash *node)
    }
 
    /*
-    * Prepare portal for the first-scan space allocations; allocate the
+    * Prepare context for the first-scan space allocations; allocate the
     * hashbucket array therein, and set each bucket "empty".
     */
    MemoryContextSwitchTo(hashtable->batchCxt);
-   StartPortalAllocMode(DefaultAllocMode, 0);
 
    hashtable->buckets = (HashJoinTuple *)
        palloc(nbuckets * sizeof(HashJoinTuple));
@@ -435,9 +431,8 @@ ExecHashTableDestroy(HashJoinTable hashtable)
            BufFileClose(hashtable->outerBatchFile[i]);
    }
 
-   /* Destroy the portal to release all working memory */
-   /* cast here is a kluge for circular includes... */
-   PortalDrop((Portal *) &hashtable->myPortal);
+   /* Release working memory (batchCxt is a child, so it goes away too) */
+   MemoryContextDelete(hashtable->hashCxt);
 
    /* And drop the control block */
    pfree(hashtable);
@@ -676,11 +671,10 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
 
    /*
     * Release all the hash buckets and tuples acquired in the prior pass,
-    * and reinitialize the portal for a new pass.
+    * and reinitialize the context for a new pass.
     */
+   MemoryContextReset(hashtable->batchCxt);
    oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
-   EndPortalAllocMode();
-   StartPortalAllocMode(DefaultAllocMode, 0);
 
    /*
     * We still use the same number of physical buckets as in the first
index ac86695ee1b44f35bcbecc6a325a3a2bc6ab0708..1ab6ae67d508b19f21dd2508e7ac10c636daebf5 100644 (file)
@@ -3,21 +3,20 @@
  * spi.c
  *             Server Programming Interface
  *
- * $Id: spi.c,v 1.46 2000/05/30 04:24:45 tgl Exp $
+ * $Id: spi.c,v 1.47 2000/06/28 03:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "executor/spi_priv.h"
 #include "access/printtup.h"
 
-static Portal _SPI_portal = (Portal) NULL;
 static _SPI_connection *_SPI_stack = NULL;
 static _SPI_connection *_SPI_current = NULL;
 static int _SPI_connected = -1;
 static int _SPI_curid = -1;
 
 DLLIMPORT uint32 SPI_processed = 0;
-DLLIMPORT SPITupleTable *SPI_tuptable;
+DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
 DLLIMPORT int SPI_result;
 
 static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
@@ -46,28 +45,6 @@ extern void ShowUsage(void);
 int
 SPI_connect()
 {
-   char        pname[64];
-   PortalVariableMemory pvmem;
-
-   /*
-    * It's possible on startup and after commit/abort. In future we'll
-    * catch commit/abort in some way...
-    */
-   strcpy(pname, "");
-   _SPI_portal = GetPortalByName(pname);
-   if (!PortalIsValid(_SPI_portal))
-   {
-       if (_SPI_stack != NULL) /* there was abort */
-           free(_SPI_stack);
-       _SPI_current = _SPI_stack = NULL;
-       _SPI_connected = _SPI_curid = -1;
-       SPI_processed = 0;
-       SPI_tuptable = NULL;
-       _SPI_portal = CreatePortal(pname);
-       if (!PortalIsValid(_SPI_portal))
-           elog(FATAL, "SPI_connect: global initialization failed");
-   }
-
    /*
     * When procedure called by Executor _SPI_curid expected to be equal
     * to _SPI_connected
@@ -99,15 +76,19 @@ SPI_connect()
    _SPI_current->processed = 0;
    _SPI_current->tuptable = NULL;
 
-   /* Create Portal for this procedure ... */
-   snprintf(pname, 64, "", _SPI_connected);
-   _SPI_current->portal = CreatePortal(pname);
-   if (!PortalIsValid(_SPI_current->portal))
-       elog(FATAL, "SPI_connect: initialization failed");
-
-   /* ... and switch to Portal' Variable memory - procedure' context */
-   pvmem = PortalGetVariableMemory(_SPI_current->portal);
-   _SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
+   /* Create memory contexts for this procedure */
+   _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
+                                                 "SPI Proc",
+                                                 ALLOCSET_DEFAULT_MINSIZE,
+                                                 ALLOCSET_DEFAULT_INITSIZE,
+                                                 ALLOCSET_DEFAULT_MAXSIZE);
+   _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
+                                                 "SPI Exec",
+                                                 ALLOCSET_DEFAULT_MINSIZE,
+                                                 ALLOCSET_DEFAULT_INITSIZE,
+                                                 ALLOCSET_DEFAULT_MAXSIZE);
+   /* ... and switch to procedure's context */
+   _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
 
    _SPI_current->savedId = GetScanCommandId();
    SetScanCommandId(GetCurrentCommandId());
@@ -127,7 +108,10 @@ SPI_finish()
 
    /* Restore memory context as it was before procedure call */
    MemoryContextSwitchTo(_SPI_current->savedcxt);
-   PortalDrop(&(_SPI_current->portal));
+
+   /* Release memory used in procedure call */
+   MemoryContextDelete(_SPI_current->execCxt);
+   MemoryContextDelete(_SPI_current->procCxt);
 
    SetScanCommandId(_SPI_current->savedId);
 
@@ -142,6 +126,7 @@ SPI_finish()
    {
        free(_SPI_stack);
        _SPI_stack = NULL;
+       _SPI_current = NULL;
    }
    else
    {
@@ -154,6 +139,25 @@ SPI_finish()
 
 }
 
+/*
+ * Clean up SPI state at transaction commit or abort (we don't care which).
+ */
+void
+AtEOXact_SPI(void)
+{
+   /*
+    * Note that memory contexts belonging to SPI stack entries will be
+    * freed automatically, so we can ignore them here.  We just need to
+    * restore our static variables to initial state.
+    */
+   if (_SPI_stack != NULL)     /* there was abort */
+       free(_SPI_stack);
+   _SPI_current = _SPI_stack = NULL;
+   _SPI_connected = _SPI_curid = -1;
+   SPI_processed = 0;
+   SPI_tuptable = NULL;
+}
+
 void
 SPI_push(void)
 {
@@ -508,61 +512,22 @@ SPI_palloc(Size size)
 void *
 SPI_repalloc(void *pointer, Size size)
 {
-   MemoryContext oldcxt = NULL;
-
-   if (_SPI_curid + 1 == _SPI_connected)       /* connected */
-   {
-       if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
-           elog(FATAL, "SPI: stack corrupted");
-       oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
-   }
-
-   pointer = repalloc(pointer, size);
-
-   if (oldcxt)
-       MemoryContextSwitchTo(oldcxt);
-
-   return pointer;
+   /* No longer need to worry which context chunk was in... */
+   return repalloc(pointer, size);
 }
 
 void
 SPI_pfree(void *pointer)
 {
-   MemoryContext oldcxt = NULL;
-
-   if (_SPI_curid + 1 == _SPI_connected)       /* connected */
-   {
-       if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
-           elog(FATAL, "SPI: stack corrupted");
-       oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
-   }
-
+   /* No longer need to worry which context chunk was in... */
    pfree(pointer);
-
-   if (oldcxt)
-       MemoryContextSwitchTo(oldcxt);
-
-   return;
 }
 
 void
 SPI_freetuple(HeapTuple tuple)
 {
-   MemoryContext oldcxt = NULL;
-
-   if (_SPI_curid + 1 == _SPI_connected)       /* connected */
-   {
-       if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
-           elog(FATAL, "SPI: stack corrupted");
-       oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
-   }
-
+   /* No longer need to worry which context tuple was in... */
    heap_freetuple(tuple);
-
-   if (oldcxt)
-       MemoryContextSwitchTo(oldcxt);
-
-   return;
 }
 
 /* =================== private functions =================== */
@@ -647,7 +612,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
        argtypes = plan->argtypes;
    }
 
-   queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs, FALSE);
+   queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
 
    _SPI_current->qtlist = queryTree_list;
 
@@ -790,7 +755,6 @@ static int
 _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 {
    Query      *parseTree = queryDesc->parsetree;
-   Plan       *plan = queryDesc->plantree;
    int         operation = queryDesc->operation;
    CommandDest dest = queryDesc->dest;
    TupleDesc   tupdesc;
@@ -875,16 +839,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 #endif
    tupdesc = ExecutorStart(queryDesc, state);
 
-   /* Don't work currently */
+   /* Don't work currently --- need to rearrange callers so that
+    * we prepare the portal before doing CreateExecutorState() etc.
+    * See pquery.c for the correct order of operations.
+    */
    if (isRetrieveIntoPortal)
    {
-       ProcessPortal(intoName,
-                     parseTree,
-                     plan,
-                     state,
-                     tupdesc,
-                     None);
-       return SPI_OK_CURSOR;
+       elog(FATAL, "SPI_select: retrieve into portal not implemented");
    }
 
    ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
@@ -920,27 +881,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 static MemoryContext
 _SPI_execmem()
 {
-   MemoryContext oldcxt;
-   PortalHeapMemory phmem;
-
-   phmem = PortalGetHeapMemory(_SPI_current->portal);
-   oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
-
-   return oldcxt;
-
+   return MemoryContextSwitchTo(_SPI_current->execCxt);
 }
 
 static MemoryContext
 _SPI_procmem()
 {
-   MemoryContext oldcxt;
-   PortalVariableMemory pvmem;
-
-   pvmem = PortalGetVariableMemory(_SPI_current->portal);
-   oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
-
-   return oldcxt;
-
+   return MemoryContextSwitchTo(_SPI_current->procCxt);
 }
 
 /*
@@ -959,7 +906,6 @@ _SPI_begin_call(bool execmem)
    if (execmem)                /* switch to the Executor memory context */
    {
        _SPI_execmem();
-       StartPortalAllocMode(DefaultAllocMode, 0);
    }
 
    return 0;
@@ -977,9 +923,10 @@ _SPI_end_call(bool procmem)
    _SPI_current->qtlist = NULL;
 
    if (procmem)                /* switch to the procedure memory context */
-   {                           /* but free Executor memory before */
-       EndPortalAllocMode();
+   {
        _SPI_procmem();
+       /* and free Executor memory */
+       MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
    }
 
    return 0;
@@ -1016,8 +963,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
    MemoryContext oldcxt = NULL;
 
    if (location == _SPI_CPLAN_PROCXT)
-       oldcxt = MemoryContextSwitchTo((MemoryContext)
-                         PortalGetVariableMemory(_SPI_current->portal));
+       oldcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
    else if (location == _SPI_CPLAN_TOPCXT)
        oldcxt = MemoryContextSwitchTo(TopMemoryContext);
 
@@ -1033,7 +979,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
    else
        newplan->argtypes = NULL;
 
-   if (location != _SPI_CPLAN_CURCXT)
+   if (oldcxt != NULL)
        MemoryContextSwitchTo(oldcxt);
 
    return newplan;
index 6b8a9d720227cce18619c02e64ee238e81bdb44b..428935f255aae54df01501136ec069357553525a 100644 (file)
@@ -4,14 +4,14 @@
 #    Makefile for lib (miscellaneous stuff)
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.13 2000/05/29 05:44:45 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.14 2000/06/28 03:31:34 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
 SRCDIR = ../..
 include ../../Makefile.global
 
-OBJS = bit.o fstack.o hasht.o lispsort.o stringinfo.o dllist.o
+OBJS = bit.o hasht.o lispsort.o stringinfo.o dllist.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/lib/fstack.c b/src/backend/lib/fstack.c
deleted file mode 100644 (file)
index 9552909..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fstack.c
- *   Fixed format stack definitions.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.14 2000/01/26 05:56:26 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-#include "lib/fstack.h"
-
-/*
- * Internal function definitions
- */
-
-/*
- * FixedItemIsValid
- *     True iff item is valid.
- */
-#define FixedItemIsValid(item) PointerIsValid(item)
-
-/*
- * FixedStackGetItemBase
- *     Returns base of enclosing structure.
- */
-#define FixedStackGetItemBase(stack, item) \
-       ((Pointer)((char *)(item) - (stack)->offset))
-
-/*
- * FixedStackGetItem
- *     Returns item of given pointer to enclosing structure.
- */
-#define FixedStackGetItem(stack, pointer) \
-       ((FixedItem)((char *)(pointer) + (stack)->offset))
-
-#define FixedStackIsValid(stack) ((bool)PointerIsValid(stack))
-
-/*
- * External functions
- */
-
-void
-FixedStackInit(FixedStack stack, Offset offset)
-{
-   AssertArg(PointerIsValid(stack));
-
-   stack->top = NULL;
-   stack->offset = offset;
-}
-
-Pointer
-FixedStackPop(FixedStack stack)
-{
-   Pointer     pointer;
-
-   AssertArg(FixedStackIsValid(stack));
-
-   if (!PointerIsValid(stack->top))
-       return NULL;
-
-   pointer = FixedStackGetItemBase(stack, stack->top);
-   stack->top = stack->top->next;
-
-   return pointer;
-}
-
-void
-FixedStackPush(FixedStack stack, Pointer pointer)
-{
-   FixedItem   item = FixedStackGetItem(stack, pointer);
-
-   AssertArg(FixedStackIsValid(stack));
-   AssertArg(PointerIsValid(pointer));
-
-   item->next = stack->top;
-   stack->top = item;
-}
-
-#ifdef USE_ASSERT_CHECKING
-/*
- * FixedStackContains
- *     True iff ordered stack contains given element.
- *
- * Note:
- *     This is inefficient.  It is intended for debugging use only.
- *
- * Exceptions:
- *     BadArg if stack is invalid.
- *     BadArg if pointer is invalid.
- */
-static bool
-FixedStackContains(FixedStack stack, Pointer pointer)
-{
-   FixedItem   next;
-   FixedItem   item;
-
-   AssertArg(FixedStackIsValid(stack));
-   AssertArg(PointerIsValid(pointer));
-
-   item = FixedStackGetItem(stack, pointer);
-
-   for (next = stack->top; FixedItemIsValid(next); next = next->next)
-   {
-       if (next == item)
-           return true;
-   }
-   return false;
-}
-
-#endif
-
-Pointer
-FixedStackGetTop(FixedStack stack)
-{
-   AssertArg(FixedStackIsValid(stack));
-
-   if (!PointerIsValid(stack->top))
-       return NULL;
-
-   return FixedStackGetItemBase(stack, stack->top);
-}
-
-Pointer
-FixedStackGetNext(FixedStack stack, Pointer pointer)
-{
-   FixedItem   item;
-
-   /* AssertArg(FixedStackIsValid(stack)); */
-   /* AssertArg(PointerIsValid(pointer)); */
-   AssertArg(FixedStackContains(stack, pointer));
-
-   item = FixedStackGetItem(stack, pointer)->next;
-
-   if (!PointerIsValid(item))
-       return NULL;
-
-   return FixedStackGetItemBase(stack, item);
-}
index 4f2df746843fdd388baadc2d7e173b3ed479fd83..379cd79502997cc0c5a614c22d0008265522eedb 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *   $Id: stringinfo.c,v 1.25 2000/04/12 17:15:11 momjian Exp $
+ *   $Id: stringinfo.c,v 1.26 2000/06/28 03:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,8 +29,6 @@ makeStringInfo(void)
    StringInfo  res;
 
    res = (StringInfo) palloc(sizeof(StringInfoData));
-   if (res == NULL)
-       elog(ERROR, "makeStringInfo: Out of memory");
 
    initStringInfo(res);
 
@@ -49,9 +47,6 @@ initStringInfo(StringInfo str)
    int         size = 256;     /* initial default buffer size */
 
    str->data = (char *) palloc(size);
-   if (str->data == NULL)
-       elog(ERROR,
-            "initStringInfo: Out of memory (%d bytes requested)", size);
    str->maxlen = size;
    str->len = 0;
    str->data[0] = '\0';
@@ -62,6 +57,11 @@ initStringInfo(StringInfo str)
  *
  * Internal routine: make sure there is enough space for 'needed' more bytes
  * ('needed' does not include the terminating null).
+ *
+ * NB: because we use repalloc() to enlarge the buffer, the string buffer
+ * will remain allocated in the same memory context that was current when
+ * initStringInfo was called, even if another context is now current.
+ * This is the desired and indeed critical behavior!
  */
 static void
 enlargeStringInfo(StringInfo str, int needed)
@@ -83,9 +83,6 @@ enlargeStringInfo(StringInfo str, int needed)
        newlen = 2 * newlen;
 
    str->data = (char *) repalloc(str->data, newlen);
-   if (str->data == NULL)
-       elog(ERROR,
-       "enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
 
    str->maxlen = newlen;
 }
index a12ae3a8a82c4b76efa15bf4f547345ec7dca257..75f6562a8f6c7062d89ac6b41f56867243554470 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.46 2000/06/09 01:11:06 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.47 2000/06/28 03:31:41 tgl Exp $
  *
  * NOTES
  *   This should be moved to a more appropriate place.  It is here
@@ -16,7 +16,7 @@
  *
  *   Builtin functions for open/close/read/write operations on large objects.
  *
- *   These functions operate in a private GlobalMemoryContext, which means
+ *   These functions operate in a private MemoryContext, which means
  *   that large object descriptors hang around until we destroy the context.
  *   That happens in lo_commit().  It'd be possible to prolong the lifetime
  *   of the context so that LO FDs are good across transactions (for example,
  *   But we'd need additional state in order to do the right thing at the
  *   end of an aborted transaction.  FDs opened during an aborted xact would
  *   still need to be closed, since they might not be pointing at valid
- *   relations at all.  For now, we'll stick with the existing documented
- *   semantics of LO FDs: they're only good within a transaction.
+ *   relations at all.  Locking semantics are also an interesting problem
+ *   if LOs stay open across transactions.  For now, we'll stick with the
+ *   existing documented semantics of LO FDs: they're only good within a
+ *   transaction.
  *
  *-------------------------------------------------------------------------
  */
@@ -56,7 +58,7 @@
  */
 static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
 
-static GlobalMemory fscxt = NULL;
+static MemoryContext fscxt = NULL;
 
 
 static int newLOfd(LargeObjectDesc *lobjCookie);
@@ -80,8 +82,13 @@ lo_open(PG_FUNCTION_ARGS)
 #endif
 
    if (fscxt == NULL)
-       fscxt = CreateGlobalMemory("Filesystem");
-   currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+       fscxt = AllocSetContextCreate(TopMemoryContext,
+                                     "Filesystem",
+                                     ALLOCSET_DEFAULT_MINSIZE,
+                                     ALLOCSET_DEFAULT_INITSIZE,
+                                     ALLOCSET_DEFAULT_MAXSIZE);
+
+   currentContext = MemoryContextSwitchTo(fscxt);
 
    lobjDesc = inv_open(lobjId, mode);
 
@@ -128,7 +135,7 @@ lo_close(PG_FUNCTION_ARGS)
 #endif
 
    Assert(fscxt != NULL);
-   currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+   currentContext = MemoryContextSwitchTo(fscxt);
 
    inv_close(cookies[fd]);
 
@@ -166,7 +173,7 @@ lo_read(int fd, char *buf, int len)
    }
 
    Assert(fscxt != NULL);
-   currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+   currentContext = MemoryContextSwitchTo(fscxt);
 
    status = inv_read(cookies[fd], buf, len);
 
@@ -193,7 +200,7 @@ lo_write(int fd, char *buf, int len)
    }
 
    Assert(fscxt != NULL);
-   currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+   currentContext = MemoryContextSwitchTo(fscxt);
 
    status = inv_write(cookies[fd], buf, len);
 
@@ -224,7 +231,7 @@ lo_lseek(PG_FUNCTION_ARGS)
    }
 
    Assert(fscxt != NULL);
-   currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+   currentContext = MemoryContextSwitchTo(fscxt);
 
    status = inv_seek(cookies[fd], offset, whence);
 
@@ -242,9 +249,13 @@ lo_creat(PG_FUNCTION_ARGS)
    Oid         lobjId;
 
    if (fscxt == NULL)
-       fscxt = CreateGlobalMemory("Filesystem");
+       fscxt = AllocSetContextCreate(TopMemoryContext,
+                                     "Filesystem",
+                                     ALLOCSET_DEFAULT_MINSIZE,
+                                     ALLOCSET_DEFAULT_INITSIZE,
+                                     ALLOCSET_DEFAULT_MAXSIZE);
 
-   currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+   currentContext = MemoryContextSwitchTo(fscxt);
 
    lobjDesc = inv_create(mode);
 
@@ -493,7 +504,7 @@ lo_commit(bool isCommit)
    if (fscxt == NULL)
        return;                 /* no LO operations in this xact */
 
-   currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+   currentContext = MemoryContextSwitchTo(fscxt);
 
    /*
     * Clean out still-open index scans (not necessary if aborting) and
@@ -512,7 +523,7 @@ lo_commit(bool isCommit)
    MemoryContextSwitchTo(currentContext);
 
    /* Release the LO memory context to prevent permanent memory leaks. */
-   GlobalMemoryDestroy(fscxt);
+   MemoryContextDelete(fscxt);
    fscxt = NULL;
 }
 
index 42d48281e08db4fe03baeaa26ca65d300fd2508a..c76889a7a72ee34ff5e518cf2af06e8934b5722f 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.32 2000/05/28 17:55:56 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.33 2000/06/28 03:31:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -135,9 +135,11 @@ PQexec(char *query)
    /* ----------------
     *  pg_exec_query_dest will put the query results in a portal which will
     *  end up on the top of the portal stack.
+    *
+    * XXX memory context manipulation needs thought here.
     * ----------------
     */
-   pg_exec_query_dest(query, Local, FALSE);
+   pg_exec_query_dest(query, Local, CurrentMemoryContext);
 
    /* ----------------
     *  pop the portal off the portal stack and return the
index 04ebd7dd57c286e8d2e8ae18cc9540f0eb6e73d4..4648fe455f7f77095dcaa079231f17d8924896cd 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.15 2000/06/11 11:39:50 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.16 2000/06/28 03:31:41 tgl Exp $
  *
  * NOTES
  *     This shouldn't be in libpq, but the monitor and some other
 
 #include "libpq/pqsignal.h"
 
+
+/*
+ * Initialize BlockSig and UnBlockSig.
+ *
+ * BlockSig is the set of signals to block when we are trying to block
+ * signals.  This includes all signals we normally expect to get, but NOT
+ * signals that should never be turned off.
+ *
+ * UnBlockSig is the set of signals to block when we don't want to block
+ * signals (is this ever nonzero??)
+ */
+void
+pqinitmask(void)
+{
+#ifdef HAVE_SIGPROCMASK
+   sigemptyset(&UnBlockSig);
+   sigfillset(&BlockSig);
+   sigdelset(&BlockSig, SIGABRT);
+   sigdelset(&BlockSig, SIGILL);
+   sigdelset(&BlockSig, SIGSEGV);
+   sigdelset(&BlockSig, SIGBUS);
+   sigdelset(&BlockSig, SIGTRAP);
+   sigdelset(&BlockSig, SIGCONT);
+   sigdelset(&BlockSig, SIGSYS);
+#else
+   UnBlockSig = 0;
+   BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) |
+       sigmask(SIGTERM) | sigmask(SIGALRM) |
+       sigmask(SIGINT) | sigmask(SIGUSR1) |
+       sigmask(SIGUSR2) | sigmask(SIGCHLD) |
+       sigmask(SIGWINCH) | sigmask(SIGFPE);
+#endif
+}
+
+
+/*
+ * Set up a signal handler
+ */
 pqsigfunc
 pqsignal(int signo, pqsigfunc func)
 {
index f3e009f5d11c97cdce3f9f72da8581ec16b7101a..fa46fac6c84a135601a4661282df5e437cc596b7 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geqo_eval.c,v 1.50 2000/05/30 00:49:46 momjian Exp $
+ * $Id: geqo_eval.c,v 1.51 2000/06/28 03:31:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,9 +19,9 @@
    =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
  */
 
-#include 
-
 #include "postgres.h"
+
+#include 
 #ifdef HAVE_LIMITS_H
 #include 
 #else
 #include "optimizer/geqo.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
-#include "utils/portal.h"
-
-
-/*
- * Variables set by geqo_eval_startup for use within a single GEQO run
- */
-static MemoryContext geqo_eval_context;
-
-/*
- * geqo_eval_startup:
- *  Must be called during geqo_main startup (before geqo_eval may be called)
- *
- * The main thing we need to do here is prepare a private memory context for
- * allocation of temp storage used while constructing a path in geqo_eval().
- * Since geqo_eval() will be called many times, we can't afford to let all
- * that memory go unreclaimed until end of statement.  We use a special
- * named portal to hold the context, so that it will be freed even if
- * we abort via elog(ERROR).  The working data is allocated in the portal's
- * heap memory context.
- */
-void
-geqo_eval_startup(void)
-{
-#define GEQO_PORTAL_NAME   ""
-   Portal      geqo_portal = GetPortalByName(GEQO_PORTAL_NAME);
-
-   if (!PortalIsValid(geqo_portal))
-   {
-       /* First time through (within current transaction, that is) */
-       geqo_portal = CreatePortal(GEQO_PORTAL_NAME);
-       Assert(PortalIsValid(geqo_portal));
-   }
+#include "utils/memutils.h"
 
-   geqo_eval_context = (MemoryContext) PortalGetHeapMemory(geqo_portal);
-}
 
 /*
  * geqo_eval
@@ -77,20 +44,30 @@ geqo_eval_startup(void)
 Cost
 geqo_eval(Query *root, Gene *tour, int num_gene)
 {
+   MemoryContext mycontext;
    MemoryContext oldcxt;
    RelOptInfo *joinrel;
    Cost        fitness;
    List       *savelist;
 
-   /* preserve root->join_rel_list, which gimme_tree changes */
-   savelist = root->join_rel_list;
-
    /*
-    * create a temporary allocation context for the path construction
-    * work
+    * Create a private memory context that will hold all temp storage
+    * allocated inside gimme_tree().
+    *
+    * Since geqo_eval() will be called many times, we can't afford to let
+    * all that memory go unreclaimed until end of statement.  Note we make
+    * the temp context a child of TransactionCommandContext, so that
+    * it will be freed even if we abort via elog(ERROR).
     */
-   oldcxt = MemoryContextSwitchTo(geqo_eval_context);
-   StartPortalAllocMode(DefaultAllocMode, 0);
+   mycontext = AllocSetContextCreate(TransactionCommandContext,
+                                     "GEQO",
+                                     ALLOCSET_DEFAULT_MINSIZE,
+                                     ALLOCSET_DEFAULT_INITSIZE,
+                                     ALLOCSET_DEFAULT_MAXSIZE);
+   oldcxt = MemoryContextSwitchTo(mycontext);
+
+   /* preserve root->join_rel_list, which gimme_tree changes */
+   savelist = root->join_rel_list;
 
    /* construct the best path for the given combination of relations */
    joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
@@ -107,8 +84,8 @@ geqo_eval(Query *root, Gene *tour, int num_gene)
    root->join_rel_list = savelist;
 
    /* release all the memory acquired within gimme_tree */
-   EndPortalAllocMode();
    MemoryContextSwitchTo(oldcxt);
+   MemoryContextDelete(mycontext);
 
    return fitness;
 }
index b00e9823bd6f21bd6bd6ec36bd0e77e59b87fad2..4f2f63572c7aa5124ec66e45da74715a1047b78b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geqo_main.c,v 1.21 2000/05/31 00:28:19 petere Exp $
+ * $Id: geqo_main.c,v 1.22 2000/06/28 03:31:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,9 +110,6 @@ geqo(Query *root)
     else
         srandom(time(NULL));
 
-/* initialize plan evaluator */
-   geqo_eval_startup();
-
 /* allocate genetic pool memory */
    pool = alloc_pool(pool_size, number_of_rels);
 
index f712d7cfecac7a18259112902dabd06d89f11047..135b6d5950ed851c0b2b3987189d78dd2eb2936e 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.149 2000/06/22 22:31:20 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.150 2000/06/28 03:31:52 tgl Exp $
  *
  * NOTES
  *
@@ -378,15 +378,38 @@ PostmasterMain(int argc, char *argv[])
     */
    umask((mode_t) 0077);
 
-   ResetAllOptions();
-
    MyProcPid = getpid();
+
+   /*
+    * Fire up essential subsystems: error and memory management
+    */
+   EnableExceptionHandling(true);
+   MemoryContextInit();
+
+   /*
+    * By default, palloc() requests in the postmaster will be allocated
+    * in the PostmasterContext, which is space that can be recycled by
+    * backends.  Allocated data that needs to be available to backends
+    * should be allocated in TopMemoryContext.
+    */
+   PostmasterContext = AllocSetContextCreate(TopMemoryContext,
+                                             "Postmaster",
+                                             ALLOCSET_DEFAULT_MINSIZE,
+                                             ALLOCSET_DEFAULT_INITSIZE,
+                                             ALLOCSET_DEFAULT_MAXSIZE);
+   MemoryContextSwitchTo(PostmasterContext);
+
+   /*
+    * Options setup
+    */
    if (getenv("PGDATA"))
        DataDir = strdup(getenv("PGDATA")); /* default value */
 
    if (getenv("PGPORT"))
        PostPortName = atoi(getenv("PGPORT"));
 
+   ResetAllOptions();
+
    /*
     * First we must scan for a -D argument to get the data dir. Then
     * read the config file. Finally, scan all the other arguments.
@@ -600,7 +623,6 @@ PostmasterMain(int argc, char *argv[])
    }
 #endif
    /* set up shared memory and semaphores */
-   EnableMemoryContext(TRUE);
    reset_shared(PostPortName);
 
    /*
@@ -662,7 +684,7 @@ PostmasterMain(int argc, char *argv[])
    /*
     * Set up signal handlers for the postmaster process.
     */
-   PG_INITMASK();
+   pqinitmask();
    PG_SETMASK(&BlockSig);
 
    pqsignal(SIGHUP, SIGHUP_handler);   /* reread config file and have children do same */
@@ -1867,6 +1889,7 @@ DoBackend(Port *port)
    /* Save port etc. for ps status */
    MyProcPort = port;
 
+   /* Reset MyProcPid to new backend's pid */
    MyProcPid = getpid();
 
    /*
@@ -1946,6 +1969,19 @@ DoBackend(Port *port)
 
    av[ac] = (char *) NULL;
 
+   /*
+    * Release postmaster's working memory context so that backend can
+    * recycle the space.  Note we couldn't do it earlier than here,
+    * because port pointer is pointing into that space!  But now we
+    * have copied all the interesting info into safe local storage.
+    */
+   MemoryContextSwitchTo(TopMemoryContext);
+   MemoryContextDelete(PostmasterContext);
+   PostmasterContext = NULL;
+
+   /*
+    * Debug: print arguments being passed to backend
+    */
    if (DebugLvl > 1)
    {
        fprintf(stderr, "%s child[%d]: starting with (",
index 40ebf3e02c2d42e1412388d4bae79f9fe321cc32..08351fe66969fc03ed9751270e679c74381248af 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.46 2000/06/15 04:09:58 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.47 2000/06/28 03:31:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/heapam.h"
-#include "lib/stringinfo.h"
+#include "utils/builtins.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_rewrite.h"
 #include "parser/parse_relation.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteSupport.h"
-#include "tcop/tcopprot.h"
 
-Oid            LastOidProcessed = InvalidOid;
-
-
-/*
- * Convert given string to a suitably quoted string constant,
- * and append it to the StringInfo buffer.
- * XXX Any MULTIBYTE considerations here?
- */
-static void
-quoteString(StringInfo buf, char *source)
-{
-   char       *current;
-
-   appendStringInfoChar(buf, '\'');
-   for (current = source; *current; current++)
-   {
-       char        ch = *current;
-
-       if (ch == '\'' || ch == '\\')
-       {
-           appendStringInfoChar(buf, '\\');
-           appendStringInfoChar(buf, ch);
-       }
-       else if (ch >= 0 && ch < ' ')
-           appendStringInfo(buf, "\\%03o", (int) ch);
-       else
-           appendStringInfoChar(buf, ch);
-   }
-   appendStringInfoChar(buf, '\'');
-}
 
 /*
  * InsertRule -
  *   takes the arguments and inserts them as attributes into the system
  *   relation "pg_rewrite"
  *
- *     MODS :  changes the value of LastOidProcessed as a side
- *             effect of inserting the rule tuple
- *
  *     ARGS :  rulname         -       name of the rule
  *             evtype          -       one of RETRIEVE,REPLACE,DELETE,APPEND
  *             evobj           -       name of relation
@@ -78,11 +47,17 @@ InsertRule(char *rulname,
           bool evinstead,
           char *actiontree)
 {
-   StringInfoData rulebuf;
    Relation    eventrel;
    Oid         eventrel_oid;
    AttrNumber  evslot_index;
-   char       *is_instead = "f";
+   int         i;
+   Datum       values[Natts_pg_rewrite];
+   char        nulls[Natts_pg_rewrite];
+   NameData    rname;
+   Relation    pg_rewrite_desc;
+   TupleDesc   tupDesc;
+   HeapTuple   tup;
+   Oid         rewriteObjectId;
 
    eventrel = heap_openr(evobj, AccessShareLock);
    eventrel_oid = RelationGetRelid(eventrel);
@@ -96,9 +71,6 @@ InsertRule(char *rulname,
        evslot_index = attnameAttNum(eventrel, evslot);
    heap_close(eventrel, AccessShareLock);
 
-   if (evinstead)
-       is_instead = "t";
-
    if (evqual == NULL)
        evqual = "<>";
 
@@ -106,23 +78,54 @@ InsertRule(char *rulname,
        elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
             rulname);
 
-   initStringInfo(&rulebuf);
-   appendStringInfo(&rulebuf,
-                    "INSERT INTO pg_rewrite (rulename, ev_type, ev_class, ev_attr, ev_action, ev_qual, is_instead) VALUES (");
-   quoteString(&rulebuf, rulname);
-   appendStringInfo(&rulebuf, ", %d::char, %u::oid, %d::int2, ",
-                    evtype, eventrel_oid, evslot_index);
-   quoteString(&rulebuf, actiontree);
-   appendStringInfo(&rulebuf, "::text, ");
-   quoteString(&rulebuf, evqual);
-   appendStringInfo(&rulebuf, "::text, '%s'::bool);",
-                    is_instead);
+   /* ----------------
+    *  Set up *nulls and *values arrays
+    * ----------------
+    */
+   MemSet(nulls, ' ', sizeof(nulls));
+
+   i = 0;
+   namestrcpy(&rname, rulname);
+   values[i++] = NameGetDatum(&rname);
+   values[i++] = CharGetDatum(evtype + '0');
+   values[i++] = ObjectIdGetDatum(eventrel_oid);
+   values[i++] = Int16GetDatum(evslot_index);
+   values[i++] = BoolGetDatum(evinstead);
+   values[i++] = PointerGetDatum(lztextin(evqual));
+   values[i++] = PointerGetDatum(lztextin(actiontree));
+
+   /* ----------------
+    *  create a new pg_rewrite tuple
+    * ----------------
+    */
+   pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
+
+   tupDesc = pg_rewrite_desc->rd_att;
+
+   tup = heap_formtuple(tupDesc,
+                        values,
+                        nulls);
+
+   heap_insert(pg_rewrite_desc, tup);
+
+   rewriteObjectId = tup->t_data->t_oid;
+
+   if (RelationGetForm(pg_rewrite_desc)->relhasindex)
+   {
+       Relation    idescs[Num_pg_rewrite_indices];
+
+       CatalogOpenIndices(Num_pg_rewrite_indices, Name_pg_rewrite_indices,
+                          idescs);
+       CatalogIndexInsert(idescs, Num_pg_rewrite_indices, pg_rewrite_desc,
+                          tup);
+       CatalogCloseIndices(Num_pg_rewrite_indices, idescs);
+   }
 
-   pg_exec_query_dest(rulebuf.data, None, true);
+   heap_freetuple(tup);
 
-   pfree(rulebuf.data);
+   heap_close(pg_rewrite_desc, RowExclusiveLock);
 
-   return LastOidProcessed;
+   return rewriteObjectId;
 }
 
 /*
index 9a5f4862410446ea80356d6ae7ea3e124dd30a26..113e0b73c596a0121f99e5e4ae2e96ede0ff5770 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.41 2000/01/26 05:56:50 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.42 2000/06/28 03:31:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,7 +136,7 @@ prs2_addToRelation(Oid relid,
     * create an in memory RewriteRule data structure which is cached by
     * every Relation descriptor. (see utils/cache/relcache.c)
     */
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
    if (qual != NULL)
        qual = copyObject(qual);
@@ -159,7 +159,7 @@ prs2_addToRelation(Oid relid,
    if (relation->rd_rules == NULL)
    {
 
-       oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+       oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
        rulelock = (RuleLock *) palloc(sizeof(RuleLock));
        rulelock->numLocks = 1;
        rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
@@ -181,7 +181,7 @@ prs2_addToRelation(Oid relid,
        rulelock = relation->rd_rules;
        numlock = rulelock->numLocks;
        /* expand, for safety reasons */
-       oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+       oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
        rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
                                  sizeof(RewriteRule *) * (numlock + 1));
        MemoryContextSwitchTo(oldcxt);
@@ -212,7 +212,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
            break;
    }
    Assert(i < numlock);
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    pfree(rulelock->rules[i]);
    MemoryContextSwitchTo(oldcxt);
    if (numlock == 1)
index 8b7ad3874bdf30a278d48436a5eb2fe467600f5c..4c590a2774bbc5bbc5c6819b38bdf2496e536183 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.51 2000/05/30 00:49:52 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.52 2000/06/28 03:31:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -262,29 +262,23 @@ InitShmem(unsigned int key, unsigned int size)
 }
 
 /*
- * ShmemAlloc -- allocate word-aligned byte string from
- *     shared memory
+ * ShmemAlloc -- allocate max-aligned byte string from shared memory
  *
  * Assumes ShmemLock and ShmemFreeStart are initialized.
  * Returns: real pointer to memory or NULL if we are out
  *     of space.  Has to return a real pointer in order
- *     to be compatable with malloc().
+ *     to be compatible with malloc().
  */
-long *
-ShmemAlloc(unsigned long size)
+void *
+ShmemAlloc(Size size)
 {
    unsigned long tmpFree;
-   long       *newSpace;
+   void       *newSpace;
 
    /*
-    * ensure space is word aligned.
-    *
-    * Word-alignment is not good enough. We have to be more conservative:
-    * doubles need 8-byte alignment. (We probably only need this on RISC
-    * platforms but this is not a big waste of space.) - ay 12/94
+    * ensure all space is adequately aligned.
     */
-   if (size % sizeof(double))
-       size += sizeof(double) - (size % sizeof(double));
+   size = MAXALIGN(size);
 
    Assert(*ShmemFreeStart);
 
@@ -293,7 +287,7 @@ ShmemAlloc(unsigned long size)
    tmpFree = *ShmemFreeStart + size;
    if (tmpFree <= ShmemSize)
    {
-       newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
+       newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
        *ShmemFreeStart += size;
    }
    else
@@ -302,7 +296,8 @@ ShmemAlloc(unsigned long size)
    SpinRelease(ShmemLock);
 
    if (!newSpace)
-       elog(NOTICE, "ShmemAlloc: out of memory ");
+       elog(NOTICE, "ShmemAlloc: out of memory");
+
    return newSpace;
 }
 
@@ -336,7 +331,7 @@ ShmemInitHash(char *name,       /* table string name for shmem index */
              int hash_flags)   /* info about infoP */
 {
    bool        found;
-   long       *location;
+   void       *location;
 
    /*
     * Hash tables allocated in shared memory have a fixed directory; it
@@ -478,12 +473,12 @@ ShmemPIDDestroy(int pid)
  *     the object is already in the shmem index (hence, already
  *     initialized).
  */
-long *
-ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
+void *
+ShmemInitStruct(char *name, Size size, bool *foundPtr)
 {
    ShmemIndexEnt *result,
                item;
-   long       *structPtr;
+   void       *structPtr;
 
    strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
    item.location = BAD_LOCATION;
@@ -498,27 +493,27 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
 #endif
 
        /*
-        * If the shmem index doesnt exist, we fake it.
+        * If the shmem index doesn't exist, we fake it.
         *
         * If we are creating the first shmem index, then let shmemalloc()
         * allocate the space for a new HTAB.  Otherwise, find the old one
         * and return that.  Notice that the ShmemIndexLock is held until
         * the shmem index has been completely initialized.
         */
-       Assert(!strcmp(name, strname));
+       Assert(strcmp(name, strname) == 0);
        if (ShmemBootstrap)
        {
            /* in POSTMASTER/Single process */
 
            *foundPtr = FALSE;
-           return (long *) ShmemAlloc(size);
+           return ShmemAlloc(size);
        }
        else
        {
            Assert(ShmemIndexOffset);
 
            *foundPtr = TRUE;
-           return (long *) MAKE_PTR(*ShmemIndexOffset);
+           return (void *) MAKE_PTR(*ShmemIndexOffset);
        }
 
 
@@ -554,12 +549,12 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
            /* let caller print its message too */
            return NULL;
        }
-       structPtr = (long *) MAKE_PTR(result->location);
+       structPtr = (void *) MAKE_PTR(result->location);
    }
    else
    {
        /* It isn't in the table yet. allocate and initialize it */
-       structPtr = ShmemAlloc((long) size);
+       structPtr = ShmemAlloc(size);
        if (!structPtr)
        {
            /* out of memory */
index 474f2616aa7f3454aa06f744cae5cc9bbe07a185..5ca3b7e8263c0aa39928794736f0afe027997f92 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.71 2000/06/17 23:41:39 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.72 2000/06/28 03:32:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1090,7 +1090,7 @@ inv_newtuple(LargeObjectDesc *obj_desc,
 
    ntup->t_len = tupsize;
    ItemPointerSet(&ntup->t_self, BufferGetBlockNumber(buffer), off);
-   LastOidProcessed = ntup->t_data->t_oid = newoid();
+   ntup->t_data->t_oid = newoid();
    TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_data->t_xmin));
    ntup->t_data->t_cmin = GetCurrentCommandId();
    StoreInvalidTransactionId(&(ntup->t_data->t_xmax));
index d18739497bd36121f4857b868d7e98d98cfa978e..12a8372c7c5d5b5b2c8c95348e253e6f41e84e4e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.69 2000/06/04 01:44:32 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.70 2000/06/28 03:32:07 tgl Exp $
  *
  * NOTES
  *   Outside modules can create a lock table and acquire/release
@@ -225,6 +225,11 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable,
  *     has its name stored in the shmem index at its creation.  It
  *     is wasteful, in this case, but not much space is involved.
  *
+ * NOTE: data structures allocated here are allocated permanently, using
+ * TopMemoryContext and shared memory.  We don't ever release them anyway,
+ * and in normal multi-backend operation the lock table structures set up
+ * by the postmaster are inherited by each backend, so they must be in
+ * TopMemoryContext.
  */
 LOCKMETHOD
 LockMethodTableInit(char *tabName,
@@ -246,22 +251,13 @@ LockMethodTableInit(char *tabName,
        return INVALID_LOCKMETHOD;
    }
 
-   /* allocate a string for the shmem index table lookup */
-   shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32));
-   if (!shmemName)
-   {
-       elog(NOTICE, "LockMethodTableInit: couldn't malloc string %s \n", tabName);
-       return INVALID_LOCKMETHOD;
-   }
+   /* Allocate a string for the shmem index table lookups. */
+   /* This is just temp space in this routine, so palloc is OK. */
+   shmemName = (char *) palloc(strlen(tabName) + 32);
 
-   /* each lock table has a non-shared header */
-   lockMethodTable = (LOCKMETHODTABLE *) palloc((unsigned) sizeof(LOCKMETHODTABLE));
-   if (!lockMethodTable)
-   {
-       elog(NOTICE, "LockMethodTableInit: couldn't malloc lock table %s\n", tabName);
-       pfree(shmemName);
-       return INVALID_LOCKMETHOD;
-   }
+   /* each lock table has a non-shared, permanent header */
+   lockMethodTable = (LOCKMETHODTABLE *)
+       MemoryContextAlloc(TopMemoryContext, sizeof(LOCKMETHODTABLE));
 
    /* ------------------------
     * find/acquire the spinlock for the table
@@ -269,7 +265,6 @@ LockMethodTableInit(char *tabName,
     */
    SpinAcquire(LockMgrLock);
 
-
    /* -----------------------
     * allocate a control structure from shared memory or attach to it
     * if it already exists.
@@ -277,7 +272,7 @@ LockMethodTableInit(char *tabName,
     */
    sprintf(shmemName, "%s (ctl)", tabName);
    lockMethodTable->ctl = (LOCKMETHODCTL *)
-       ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found);
+       ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
 
    if (!lockMethodTable->ctl)
    {
@@ -910,7 +905,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
    LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode);
 
    old_status = pstrdup(get_ps_display());
-   new_status = palloc(strlen(get_ps_display()) + 10);
+   new_status = (char *) palloc(strlen(get_ps_display()) + 10);
    strcpy(new_status, get_ps_display());
    strcat(new_status, " waiting");
    set_ps_display(new_status);
index ed41e43727cbd3d09480105e42c7831775b8e4cd..de2b406f87cf0d6c57885fa63d39b7f840cff762 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,7 @@
  *     This is so that we can support more backends. (system-wide semaphore
  *     sets run out pretty fast.)                -ay 4/95
  *
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
  */
 #include 
 #include 
@@ -119,7 +119,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
 
    /* attach to the free list */
    ProcGlobal = (PROC_HDR *)
-       ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
+       ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
 
    /* --------------------
     * We're the first - initialize.
@@ -185,7 +185,7 @@ InitProcess(IPCKey key)
 
    /* attach to the free list */
    ProcGlobal = (PROC_HDR *)
-       ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
+       ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
    if (!found)
    {
        /* this should not happen. InitProcGlobal() is called before this. */
@@ -218,7 +218,7 @@ InitProcess(IPCKey key)
         * cleanup dead processes).
         */
 
-       MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
+       MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
        if (!MyProc)
        {
            SpinRelease(ProcStructLock);
@@ -458,7 +458,7 @@ ProcQueueAlloc(char *name)
 {
    bool        found;
    PROC_QUEUE *queue = (PROC_QUEUE *)
-   ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
+       ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
 
    if (!queue)
        return NULL;
index 19433ae29a089c0d4febfda6742c9fe8e1aa7809..de51e703f8b61f63213433b7bd3c79b7de953572 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.71 2000/06/19 23:37:08 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.72 2000/06/28 03:32:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -94,19 +94,15 @@ static BlockNumber _mdnblocks(File file, Size blcksz);
 int
 mdinit()
 {
-   MemoryContext oldcxt;
    int         i;
 
-   MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
-   if (MdCxt == (MemoryContext) NULL)
-       return SM_FAIL;
-
-   oldcxt = MemoryContextSwitchTo(MdCxt);
-   Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
-   MemoryContextSwitchTo(oldcxt);
+   MdCxt = AllocSetContextCreate(TopMemoryContext,
+                                 "MdSmgr",
+                                 ALLOCSET_DEFAULT_MINSIZE,
+                                 ALLOCSET_DEFAULT_INITSIZE,
+                                 ALLOCSET_DEFAULT_MAXSIZE);
 
-   if (Md_fdvec == (MdfdVec *) NULL)
-       return SM_FAIL;
+   Md_fdvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
 
    MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
 
@@ -208,7 +204,6 @@ mdunlink(Relation reln)
    int         nblocks;
    int         fd;
    MdfdVec    *v;
-   MemoryContext oldcxt;
 
    /*
     * If the relation is already unlinked,we have nothing to do any more.
@@ -238,7 +233,6 @@ mdunlink(Relation reln)
 
    Md_fdvec[fd].mdfd_flags = (uint16) 0;
 
-   oldcxt = MemoryContextSwitchTo(MdCxt);
 #ifndef LET_OS_MANAGE_FILESIZE
    for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
    {
@@ -256,7 +250,6 @@ mdunlink(Relation reln)
    FileTruncate(v->mdfd_vfd, 0);
    FileUnlink(v->mdfd_vfd);
 #endif
-   MemoryContextSwitchTo(oldcxt);
 
    _fdvec_free(fd);
 
@@ -400,9 +393,7 @@ static void
 mdclose_fd(int fd)
 {
    MdfdVec    *v;
-   MemoryContext oldcxt;
 
-   oldcxt = MemoryContextSwitchTo(MdCxt);
 #ifndef LET_OS_MANAGE_FILESIZE
    for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
    {
@@ -446,7 +437,6 @@ mdclose_fd(int fd)
        }
    }
 #endif
-   MemoryContextSwitchTo(oldcxt);
 
    _fdvec_free(fd);
 }
@@ -751,11 +741,8 @@ mdtruncate(Relation reln, int nblocks)
    int         curnblk;
    int         fd;
    MdfdVec    *v;
-
 #ifndef LET_OS_MANAGE_FILESIZE
-   MemoryContext oldcxt;
    int         priorblocks;
-
 #endif
 
    /*
@@ -772,7 +759,6 @@ mdtruncate(Relation reln, int nblocks)
    v = &Md_fdvec[fd];
 
 #ifndef LET_OS_MANAGE_FILESIZE
-   oldcxt = MemoryContextSwitchTo(MdCxt);
    priorblocks = 0;
    while (v != (MdfdVec *) NULL)
    {
@@ -825,7 +811,6 @@ mdtruncate(Relation reln, int nblocks)
        }
        priorblocks += RELSEG_SIZE;
    }
-   MemoryContextSwitchTo(oldcxt);
 #else
    if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
        return -1;
@@ -833,8 +818,7 @@ mdtruncate(Relation reln, int nblocks)
 #endif
 
    return nblocks;
-
-}  /* mdtruncate */
+}
 
 /*
  * mdcommit() -- Commit a transaction.
@@ -907,7 +891,6 @@ _fdvec_alloc()
    MdfdVec    *nvec;
    int         fdvec,
                i;
-   MemoryContext oldcxt;
 
    if (Md_Free >= 0)           /* get from free list */
    {
@@ -930,15 +913,11 @@ _fdvec_alloc()
 
    Nfds *= 2;
 
-   oldcxt = MemoryContextSwitchTo(MdCxt);
-
-   nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
+   nvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
    MemSet(nvec, 0, Nfds * sizeof(MdfdVec));
-   memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
+   memcpy(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
    pfree(Md_fdvec);
 
-   MemoryContextSwitchTo(oldcxt);
-
    Md_fdvec = nvec;
 
    /* Set new free list */
@@ -976,7 +955,6 @@ _fdvec_free(int fdvec)
 static MdfdVec *
 _mdfd_openseg(Relation reln, int segno, int oflags)
 {
-   MemoryContext oldcxt;
    MdfdVec    *v;
    int         fd;
    char       *path,
@@ -1003,9 +981,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags)
        return (MdfdVec *) NULL;
 
    /* allocate an mdfdvec entry for it */
-   oldcxt = MemoryContextSwitchTo(MdCxt);
-   v = (MdfdVec *) palloc(sizeof(MdfdVec));
-   MemoryContextSwitchTo(oldcxt);
+   v = (MdfdVec *) MemoryContextAlloc(MdCxt, sizeof(MdfdVec));
 
    /* fill the entry */
    v->mdfd_vfd = fd;
index 9209b6509f2e840cb1a70235e6ac61824e70b458..e018114a5daf6e78c5db4ab22f01e2f6203110b5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.161 2000/06/22 22:31:20 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.162 2000/06/28 03:32:18 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -79,7 +79,6 @@ bool Log_connections = false;
 CommandDest whereToSendOutput = Debug;
 
 
-extern void BaseInit(void);
 extern void StartupXLOG(void);
 extern void ShutdownXLOG(void);
 
@@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS);
 extern char XLogDir[];
 extern char ControlFilePath[];
 
-extern int lockingOff;
-extern int NBuffers;
+static bool    dontExecute = false;
 
-int            dontExecute = 0;
 static bool IsEmptyQuery = false;
 
 /* note: these declarations had better match tcopprot.h */
@@ -101,8 +98,6 @@ bool     Warn_restart_ready = false;
 bool       InError = false;
 bool       ExitAfterAbort = false;
 
-extern int NBuffers;
-
 static bool EchoQuery = false; /* default don't echo */
 char       pg_pathname[MAXPGPATH];
 FILE      *StatFp = NULL;
@@ -133,7 +128,6 @@ int         XfuncMode = 0;
 static int InteractiveBackend(StringInfo inBuf);
 static int SocketBackend(StringInfo inBuf);
 static int ReadCommand(StringInfo inBuf);
-static void pg_exec_query(char *query_string);
 static void SigHupHandler(SIGNAL_ARGS);
 static void FloatExceptionHandler(SIGNAL_ARGS);
 static void quickdie(SIGNAL_ARGS);
@@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf)
 static int
 ReadCommand(StringInfo inBuf)
 {
-   MemoryContext oldcontext;
    int         result;
 
-   /*
-    * Make sure any expansion of inBuf happens in permanent memory
-    * context, so that we can keep using it for future command cycles.
-    */
-   oldcontext = MemoryContextSwitchTo(TopMemoryContext);
    if (IsUnderPostmaster)
        result = SocketBackend(inBuf);
    else
        result = InteractiveBackend(inBuf);
-   MemoryContextSwitchTo(oldcontext);
    return result;
 }
 
@@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf)
  * multiple queries and/or the rewriter might expand one query to several.
  */
 List *
-pg_parse_and_rewrite(char *query_string,       /* string to execute */
-                    Oid *typev,/* argument types */
-                    int nargs, /* number of arguments */
-                    bool aclOverride)
+pg_parse_and_rewrite(char *query_string,   /* string to execute */
+                    Oid *typev,            /* parameter types */
+                    int nargs)             /* number of parameters */
 {
    List       *querytree_list;
    List       *querytree_list_item;
@@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string,       /* string to execute */
 
    querytree_list = new_list;
 
-   /* ----------------
-    *  (3) If ACL override is requested, mark queries for no ACL check.
-    * ----------------
-    */
-   if (aclOverride)
-   {
-       foreach(querytree_list_item, querytree_list)
-       {
-           List       *l;
-
-           querytree = (Query *) lfirst(querytree_list_item);
-
-           if (querytree->commandType == CMD_UTILITY)
-               continue;
-
-           foreach(l, querytree->rtable)
-           {
-               RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
-
-               rte->skipAcl = TRUE;
-           }
-       }
-   }
-
    if (Debug_print_rewritten)
    {
        if (Debug_pretty_print)
@@ -516,63 +478,66 @@ pg_plan_query(Query *querytree)
 
 
 /* ----------------------------------------------------------------
- *     pg_exec_query()
+ *     pg_exec_query_dest()
  *
  *     Takes a querystring, runs the parser/utilities or
- *     parser/planner/executor over it as necessary
- *     Begin Transaction Should have been called before this
- *     and CommitTransaction After this is called
- *     This is strictly because we do not allow for nested xactions.
+ *     parser/planner/executor over it as necessary.
+ *
+ * Assumptions:
+ *
+ * Caller is responsible for calling StartTransactionCommand() beforehand
+ * and CommitTransactionCommand() afterwards (if successful).
+ *
+ * The CurrentMemoryContext at entry references a context that is
+ * appropriate for execution of individual queries (typically this will be
+ * TransactionCommandContext).  Note that this routine resets that context
+ * after each individual query, so don't store anything there that
+ * must outlive the call!
  *
- *     NON-OBVIOUS-RESTRICTIONS
- *     this function _MUST_ allocate a new "parsetree" each time,
- *     since it may be stored in a named portal and should not
- *     change its value.
+ * parse_context references a context suitable for holding the
+ * parse/rewrite trees (typically this will be QueryContext).
+ * This context must be longer-lived than the CurrentMemoryContext!
+ * In fact, if the query string might contain BEGIN/COMMIT commands,
+ * parse_context had better outlive TopTransactionContext!
+ *
+ * We could have hard-wired knowledge about QueryContext and
+ * TransactionCommandContext into this routine, but it seems better
+ * not to, in case callers from outside this module need to use some
+ * other contexts.
  *
  * ----------------------------------------------------------------
  */
 
-static void
-pg_exec_query(char *query_string)
-{
-   pg_exec_query_dest(query_string, whereToSendOutput, FALSE);
-}
-
-#ifdef NOT_USED
-void
-pg_exec_query_acl_override(char *query_string)
-{
-   pg_exec_query_dest(query_string, whereToSendOutput, TRUE);
-}
-#endif
-
 void
 pg_exec_query_dest(char *query_string, /* string to execute */
                   CommandDest dest,    /* where results should go */
-                  bool aclOverride)    /* to give utility commands power
-                                        * of superusers */
+                  MemoryContext parse_context) /* context for parsetrees */
 {
-   List       *querytree_list;
+   MemoryContext oldcontext;
+   List       *querytree_list,
+              *querytree_item;
 
-   /* parse and rewrite the queries */
-   querytree_list = pg_parse_and_rewrite(query_string, NULL, 0,
-                                         aclOverride);
+   /*
+    * Switch to appropriate context for constructing parsetrees.
+    */
+   oldcontext = MemoryContextSwitchTo(parse_context);
 
    /*
-    * NOTE: we do not use "foreach" here because we want to be sure the
-    * list pointer has been advanced before the query is executed. We
-    * need to do that because VACUUM has a nasty little habit of doing
-    * CommitTransactionCommand at startup, and that will release the
-    * memory holding our parse list :-(.  This needs a better solution
-    * --- currently, the code will crash if someone submits "vacuum;
-    * something-else" in a single query string.  But memory allocation
-    * needs redesigned anyway, so this will have to do for now.
+    * Parse and rewrite the query or queries.
     */
-   while (querytree_list)
-   {
-       Query      *querytree = (Query *) lfirst(querytree_list);
+   querytree_list = pg_parse_and_rewrite(query_string, NULL, 0);
 
-       querytree_list = lnext(querytree_list);
+   /*
+    * Switch back to execution context for planning and execution.
+    */
+   MemoryContextSwitchTo(oldcontext);
+
+   /*
+    * Run through the query or queries and execute each one.
+    */
+   foreach(querytree_item, querytree_list)
+   {
+       Query      *querytree = (Query *) lfirst(querytree_item);
 
        /* if we got a cancel signal in parsing or prior command, quit */
        if (QueryCancel)
@@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string, /* string to execute */
            if (Show_executor_stats)
                ResetUsage();
 
-           if (DebugLvl > 1)
-               elog(DEBUG, "ProcessQuery");
-           ProcessQuery(querytree, plan, dest);
+           if (dontExecute)
+           {
+               /* don't execute it, just show the query plan */
+               print_plan(plan, querytree);
+           }
+           else
+           {
+               if (DebugLvl > 1)
+                   elog(DEBUG, "ProcessQuery");
+               ProcessQuery(querytree, plan, dest);
+           }
 
            if (Show_executor_stats)
            {
@@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string, /* string to execute */
         * between queries so that the effects of early queries are
         * visible to subsequent ones.
         */
-
        CommandCounterIncrement();
+       /*
+        * Also, clear the execution context to recover temporary
+        * memory used by the query.  NOTE: if query string contains
+        * BEGIN/COMMIT transaction commands, execution context may
+        * now be different from what we were originally passed;
+        * so be careful to clear current context not "oldcontext".
+        */
+       MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
    }
 }
 
@@ -821,6 +801,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
    extern char *optarg;
    extern int  DebugLvl;
 
+   /*
+    * Fire up essential subsystems: error and memory management
+    *
+    * If we are running under the postmaster, this is done already.
+    */
+   if (!IsUnderPostmaster)
+   {
+       EnableExceptionHandling(true);
+       MemoryContextInit();
+   }
+
    /*
     * Set default values for command-line options.
     */
@@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
                break;
 
            case 'i':
-               dontExecute = 1;
+               dontExecute = true;
                break;
 
            case 'L':
@@ -1182,11 +1173,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
     *
     * Note that postmaster already blocked ALL signals to make us happy.
     */
-   if (!IsUnderPostmaster)
-   {
-       PG_INITMASK();
-       PG_SETMASK(&BlockSig);
-   }
+   pqinitmask();
 
 #ifdef HAVE_SIGPROCMASK
    sigdelset(&BlockSig, SIGUSR1);
@@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
    BlockSig &= ~(sigmask(SIGUSR1));
 #endif
 
+   PG_SETMASK(&BlockSig);      /* block everything except SIGUSR1 */
+
    pqsignal(SIGHUP, SigHupHandler);    /* set flag to read config file */
    pqsignal(SIGINT, QueryCancelHandler);       /* cancel current query */
    pqsignal(SIGQUIT, handle_warn);     /* handle error */
@@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
    pqsignal(SIGTTOU, SIG_DFL);
    pqsignal(SIGCONT, SIG_DFL);
 
-   PG_SETMASK(&BlockSig);      /* block everything except SIGUSR1 */
-
    /*
     * Get user name (needed now in case it is the default database name)
     * and check command line validity
@@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
    on_shmem_exit(remove_all_temp_relations, NULL);
 
-   {
-       MemoryContext oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-
-       parser_input = makeStringInfo();        /* initialize input buffer */
-       MemoryContextSwitchTo(oldcontext);
-   }
-
    /*
     * Send this backend's cancellation info to the frontend.
     */
@@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.161 $ $Date: 2000/06/22 22:31:20 $\n");
+       puts("$Revision: 1.162 $ $Date: 2000/06/28 03:32:18 $\n");
    }
 
    /*
@@ -1397,6 +1377,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
    SetProcessingMode(NormalProcessing);
 
+   /*
+    * Create the memory context we will use in the main loop.
+    *
+    * QueryContext is reset once per iteration of the main loop,
+    * ie, upon completion of processing of each supplied query string.
+    * It can therefore be used for any data that should live just as
+    * long as the query string --- parse trees, for example.
+    */
+   QueryContext = AllocSetContextCreate(TopMemoryContext,
+                                        "QueryContext",
+                                        ALLOCSET_DEFAULT_MINSIZE,
+                                        ALLOCSET_DEFAULT_INITSIZE,
+                                        ALLOCSET_DEFAULT_MAXSIZE);
+
    /*
     * POSTGRES main processing loop begins here
     *
@@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
    if (sigsetjmp(Warn_restart, 1) != 0)
    {
-       /* Make sure we are in a valid memory context */
-       MemoryContextSwitchTo(TopMemoryContext);
+       /*
+        * Make sure we are in a valid memory context during recovery.
+        *
+        * We use ErrorContext in hopes that it will have some free space
+        * even if we're otherwise up against it...
+        */
+       MemoryContextSwitchTo(ErrorContext);
 
        if (DebugLvl >= 1)
            elog(DEBUG, "AbortCurrentTransaction");
        AbortCurrentTransaction();
-       InError = false;
+
        if (ExitAfterAbort)
        {
            ProcReleaseLocks(); /* Just to be sure... */
            proc_exit(0);
        }
+       /*
+        * If we recovered successfully, return to normal top-level context
+        * and clear ErrorContext for next time.
+        */
+       MemoryContextSwitchTo(TopMemoryContext);
+       MemoryContextResetAndDeleteChildren(ErrorContext);
+       InError = false;
    }
 
    Warn_restart_ready = true;  /* we can now handle elog(ERROR) */
@@ -1430,7 +1436,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
    for (;;)
    {
-       set_ps_display("idle");
+       /*
+        * Release storage left over from prior query cycle, and
+        * create a new query input buffer in the cleared QueryContext.
+        */
+       MemoryContextSwitchTo(QueryContext);
+       MemoryContextResetAndDeleteChildren(QueryContext);
+
+       parser_input = makeStringInfo();
 
        /* XXX this could be moved after ReadCommand below to get more
         * sensical behaviour */
@@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
         *   (3) read a command (loop blocks here)
         * ----------------
         */
+       set_ps_display("idle");
+
        firstchar = ReadCommand(parser_input);
 
        QueryCancel = false;    /* forget any earlier CANCEL signal */
@@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
                        elog(DEBUG, "StartTransactionCommand");
                    StartTransactionCommand();
 
-                   pg_exec_query(parser_input->data);
+                   pg_exec_query_dest(parser_input->data,
+                                      whereToSendOutput,
+                                      QueryContext);
 
                    /*
                     * Invoke IMMEDIATE constraint triggers
@@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
         *   (6) commit the current transaction
         *
         *   Note: if we had an empty input buffer, then we didn't
-        *   call pg_exec_query, so we don't bother to commit this transaction.
+        *   call pg_exec_query_dest, so we don't bother to commit
+        *   this transaction.
         * ----------------
         */
        if (!IsEmptyQuery)
@@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 #ifdef SHOW_MEMORY_STATS
            /* print global-context stats at each commit for leak tracking */
            if (ShowStats)
-               GlobalMemoryStats();
+               MemoryContextStats(TopMemoryContext);
 #endif
        }
        else
index b26923b6f14b556d70cc8c5c76ab6dc18a9b3625..9e52930e20f8dc4c16d145038822bca6787e11fe 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.34 2000/06/12 03:40:40 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.35 2000/06/28 03:32:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,6 @@
 #include "utils/ps_status.h"
 
 static char *CreateOperationTag(int operationType);
-static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
-                Node *limcount);
 
 
 /* ----------------------------------------------------------------
@@ -115,7 +113,7 @@ CreateOperationTag(int operationType)
        default:
            elog(DEBUG, "CreateOperationTag: unknown operation type %d",
                 operationType);
-           tag = NULL;
+           tag = "???";
            break;
    }
 
@@ -123,31 +121,18 @@ CreateOperationTag(int operationType)
 }
 
 /* ----------------
- *     ProcessPortal
+ *     PreparePortal
  * ----------------
  */
-
-void
-ProcessPortal(char *portalName,
-             Query *parseTree,
-             Plan *plan,
-             EState *state,
-             TupleDesc attinfo,
-             CommandDest dest)
+Portal
+PreparePortal(char *portalName)
 {
    Portal      portal;
-   MemoryContext portalContext;
 
    /* ----------------
-    *   Check for reserved or already-in-use portal name.
+    *   Check for already-in-use portal name.
     * ----------------
     */
-
-   if (PortalNameIsSpecial(portalName))
-       elog(ERROR,
-            "The portal name \"%s\" is reserved for internal use",
-            portalName);
-
    portal = GetPortalByName(portalName);
    if (PortalIsValid(portal))
    {
@@ -158,70 +143,39 @@ ProcessPortal(char *portalName,
    }
 
    /* ----------------
-    *   Convert the current blank portal into the user-specified
-    *   portal and initialize the state and query descriptor.
-    *
-    *   Since the parsetree has been created in the current blank portal,
-    *   we don't have to do any work to copy it into the user-named portal.
+    *   Create the new portal and make its memory context active.
     * ----------------
     */
+   portal = CreatePortal(portalName);
 
-   portal = BlankPortalAssignName(portalName);
-
-   PortalSetQuery(portal,
-                  CreateQueryDesc(parseTree, plan, dest),
-                  attinfo,
-                  state,
-                  PortalCleanup);
+   MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
-   /* ----------------
-    *  Now create a new blank portal and switch to it.
-    *  Otherwise, the new named portal will be cleaned at statement end.
-    *
-    *  Note: portals will only be supported within a BEGIN...END
-    *  block in the near future.  Later, someone will fix it to
-    *  do what is possible across transaction boundries. -hirohama
-    * ----------------
-    */
-   portalContext = (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL));
-
-   MemoryContextSwitchTo(portalContext);
-
-   StartPortalAllocMode(DefaultAllocMode, 0);
+   return portal;
 }
 
 
 /* ----------------------------------------------------------------
- *     ProcessQueryDesc
+ *     ProcessQuery
  *
- *     Read the comments for ProcessQuery() below...
+ *     Execute a plan, the non-parallel version
  * ----------------------------------------------------------------
  */
-static void
-ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
+void
+ProcessQuery(Query *parsetree,
+            Plan *plan,
+            CommandDest dest)
 {
-   Query      *parseTree;
-   Plan       *plan;
-   int         operation;
-   char       *tag = NULL;
-   EState     *state;
-   TupleDesc   attinfo;
-
+   int         operation = parsetree->commandType;
+   char       *tag;
    bool        isRetrieveIntoPortal;
    bool        isRetrieveIntoRelation;
+   Portal      portal = NULL;
    char       *intoName = NULL;
-   CommandDest dest;
-
-   /* ----------------
-    *  get info from the query desc
-    * ----------------
-    */
-   parseTree = queryDesc->parsetree;
-   plan = queryDesc->plantree;
+   QueryDesc  *queryDesc;
+   EState     *state;
+   TupleDesc   attinfo;
 
-   operation = queryDesc->operation;
    set_ps_display(tag = CreateOperationTag(operation));
-   dest = queryDesc->dest;
 
    /* ----------------
     *  initialize portal/into relation status
@@ -232,11 +186,11 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
 
    if (operation == CMD_SELECT)
    {
-       if (parseTree->isPortal)
+       if (parsetree->isPortal)
        {
            isRetrieveIntoPortal = true;
-           intoName = parseTree->into;
-           if (parseTree->isBinary)
+           intoName = parsetree->into;
+           if (parsetree->isBinary)
            {
 
                /*
@@ -244,19 +198,38 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
                 * (externalized form) to RemoteInternal (internalized
                 * form)
                 */
-               dest = queryDesc->dest = RemoteInternal;
+               dest = RemoteInternal;
            }
        }
-       else if (parseTree->into != NULL)
+       else if (parsetree->into != NULL)
        {
            /* select into table */
            isRetrieveIntoRelation = true;
        }
+   }
 
+   /* ----------------
+    *  If retrieving into a portal, set up the portal and copy
+    *  the parsetree and plan into its memory context.
+    * ----------------
+    */
+   if (isRetrieveIntoPortal)
+   {
+       portal = PreparePortal(intoName);
+       /* CurrentMemoryContext is now pointing to portal's context */
+       parsetree = copyObject(parsetree);
+       plan = copyObject(plan);
    }
 
    /* ----------------
-    *  when performing a retrieve into, we override the normal
+    *  Now we can create the QueryDesc object (this is also in
+    *  the portal context, if portal retrieve).
+    * ----------------
+    */
+   queryDesc = CreateQueryDesc(parsetree, plan, dest);
+
+   /* ----------------
+    *  When performing a retrieve into, we override the normal
     *  communication destination during the processing of the
     *  the query.  This only affects the tuple-output function
     *  - the correct destination will still see BeginCommand()
@@ -293,26 +266,19 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
                 dest);
 
    /* ----------------
-    *  Named portals do not do a "fetch all" initially, so now
-    *  we return since ExecMain has been called with EXEC_START
-    *  to initialize the query plan.
-    *
-    *  Note: ProcessPortal transforms the current "blank" portal
-    *        into a named portal and creates a new blank portal so
-    *        everything we allocated in the current "blank" memory
-    *        context will be preserved across queries.  -cim 2/22/91
+    *  If retrieve into portal, stop now; we do not run the plan
+    *  until a FETCH command is received.
     * ----------------
     */
    if (isRetrieveIntoPortal)
    {
-       PortalExecutorHeapMemory = NULL;
+       PortalSetQuery(portal,
+                      queryDesc,
+                      attinfo,
+                      state,
+                      PortalCleanup);
 
-       ProcessPortal(intoName,
-                     parseTree,
-                     plan,
-                     state,
-                     attinfo,
-                     dest);
+       MemoryContextSwitchTo(TransactionCommandContext);
 
        EndCommand(tag, dest);
        return;
@@ -323,14 +289,14 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
     *   actually run the plan..
     * ----------------
     */
-   ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
+   ExecutorRun(queryDesc, state, EXEC_RUN,
+               parsetree->limitOffset, parsetree->limitCount);
 
    /* save infos for EndCommand */
    UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
 
    /* ----------------
-    *   now, we close down all the scans and free allocated resources...
-    * with ExecutorEnd()
+    *   Now, we close down all the scans and free allocated resources.
     * ----------------
     */
    ExecutorEnd(queryDesc, state);
@@ -341,31 +307,3 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
     */
    EndCommand(tag, dest);
 }
-
-/* ----------------------------------------------------------------
- *     ProcessQuery
- *
- *     Execute a plan, the non-parallel version
- * ----------------------------------------------------------------
- */
-
-void
-ProcessQuery(Query *parsetree,
-            Plan *plan,
-            CommandDest dest)
-{
-   QueryDesc  *queryDesc;
-   extern int  dontExecute;    /* from postgres.c */
-   extern void print_plan(Plan *p, Query *parsetree);  /* from print.c */
-
-   queryDesc = CreateQueryDesc(parsetree, plan, dest);
-
-   if (dontExecute)
-   {
-       /* don't execute it, just show the query plan */
-       print_plan(plan, parsetree);
-   }
-   else
-       ProcessQueryDesc(queryDesc, parsetree->limitOffset,
-                        parsetree->limitCount);
-}
index a1c2d5b7bbb9014e6356debb11b651c00fc070b8..d6730006784f52ff5325ff2be3e70de96f7e5de2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.67 2000/06/19 03:54:31 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.68 2000/06/28 03:32:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,10 +60,6 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
 
 static CatCache *Caches = NULL; /* head of list of caches */
 
-GlobalMemory CacheCxt;         /* context in which caches are allocated */
-
-/* CacheCxt is global because relcache uses it too. */
-
 
 /* ----------------
  *     EQPROC is used in CatalogCacheInitializeCache to find the equality
@@ -135,6 +131,28 @@ cc_hashname(PG_FUNCTION_ARGS)
 }
 
 
+/*
+ * Standard routine for creating cache context if it doesn't exist yet
+ *
+ * There are a lot of places (probably far more than necessary) that check
+ * whether CacheMemoryContext exists yet and want to create it if not.
+ * We centralize knowledge of exactly how to create it here.
+ */
+void
+CreateCacheMemoryContext(void)
+{
+   /* Purely for paranoia, check that context doesn't exist;
+    * caller probably did so already.
+    */
+   if (!CacheMemoryContext)
+       CacheMemoryContext = AllocSetContextCreate(TopMemoryContext,
+                                                  "CacheMemoryContext",
+                                                  ALLOCSET_DEFAULT_MINSIZE,
+                                                  ALLOCSET_DEFAULT_INITSIZE,
+                                                  ALLOCSET_DEFAULT_MAXSIZE);
+}
+
+
 /* --------------------------------
  *     CatalogCacheInitializeCache
  * --------------------------------
@@ -183,9 +201,10 @@ CatalogCacheInitializeCache(CatCache * cache,
     *  do not vanish at the end of a transaction
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
+
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /* ----------------
     *  If no relation was passed we must open it to get access to
@@ -415,7 +434,7 @@ CatalogCacheComputeTupleHashIndex(CatCache * cacheInOutP,
 /* --------------------------------
  *     CatCacheRemoveCTup
  *
- *     NB: assumes caller has switched to CacheCxt
+ *     NB: assumes caller has switched to CacheMemoryContext
  * --------------------------------
  */
 static void
@@ -477,9 +496,10 @@ CatalogCacheIdInvalidate(int cacheId,  /* XXX */
     *  switch to the cache context for our memory allocations
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
+
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /* ----------------
     *  inspect every cache that could contain the tuple
@@ -552,10 +572,10 @@ ResetSystemCache()
     *  do not vanish at the end of a transaction
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /* ----------------
     *  here we purge the contents of all the caches
@@ -681,10 +701,10 @@ InitSysCache(char *relname,
     *  do not vanish at the end of a transaction
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /* ----------------
     *  allocate a new cache structure
@@ -839,14 +859,14 @@ SearchSelfReferences(CatCache * cache)
            HeapScanDesc sd;
            MemoryContext oldcxt;
 
-           if (!CacheCxt)
-               CacheCxt = CreateGlobalMemory("Cache");
            rel = heap_open(cache->relationId, AccessShareLock);
            sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
            ntp = heap_getnext(sd, 0);
            if (!HeapTupleIsValid(ntp))
                elog(ERROR, "SearchSelfReferences: tuple not found");
-           oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+           if (!CacheMemoryContext)
+               CreateCacheMemoryContext();
+           oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
            indexSelfTuple = heap_copytuple(ntp);
            MemoryContextSwitchTo(oldcxt);
            heap_endscan(sd);
@@ -868,14 +888,14 @@ SearchSelfReferences(CatCache * cache)
            HeapScanDesc sd;
            MemoryContext oldcxt;
 
-           if (!CacheCxt)
-               CacheCxt = CreateGlobalMemory("Cache");
            rel = heap_open(cache->relationId, AccessShareLock);
            sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
            ntp = heap_getnext(sd, 0);
            if (!HeapTupleIsValid(ntp))
                elog(ERROR, "SearchSelfReferences: tuple not found");
-           oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+           if (!CacheMemoryContext)
+               CreateCacheMemoryContext();
+           oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
            operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
            MemoryContextSwitchTo(oldcxt);
            heap_endscan(sd);
@@ -908,7 +928,6 @@ SearchSysCache(CatCache * cache,
    CatCTup    *nct2;
    Dlelem     *elt;
    HeapTuple   ntp = NULL;
-
    Relation    relation;
    MemoryContext oldcxt;
 
@@ -1020,10 +1039,10 @@ SearchSysCache(CatCache * cache,
     * ----------------
     */
 
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /* ----------------
     *  Scan the relation to find the tuple.  If there's an index, and
@@ -1060,12 +1079,13 @@ SearchSysCache(CatCache * cache,
         */
        if (HeapTupleIsValid(indextp))
        {
-           MemoryContextSwitchTo((MemoryContext) CacheCxt);
+           MemoryContextSwitchTo(CacheMemoryContext);
            ntp = heap_copytuple(indextp);
+           /* this switch is probably not needed anymore: */
            MemoryContextSwitchTo(oldcxt);
            heap_freetuple(indextp);
        }
-       MemoryContextSwitchTo((MemoryContext) CacheCxt);
+       MemoryContextSwitchTo(CacheMemoryContext);
    }
    else
    {
@@ -1084,7 +1104,7 @@ SearchSysCache(CatCache * cache,
 
        ntp = heap_getnext(sd, 0);
 
-       MemoryContextSwitchTo((MemoryContext) CacheCxt);
+       MemoryContextSwitchTo(CacheMemoryContext);
 
        if (HeapTupleIsValid(ntp))
        {
@@ -1097,7 +1117,7 @@ SearchSysCache(CatCache * cache,
 
        heap_endscan(sd);
 
-       MemoryContextSwitchTo((MemoryContext) CacheCxt);
+       MemoryContextSwitchTo(CacheMemoryContext);
    }
 
    cache->busy = false;
@@ -1205,9 +1225,10 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
     *  switch to the cache memory context
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
+
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /* ----------------
     *  for each cache
index a063534c0db25c0980b9d2014757af8bcf32729a..b0ee20fce986f810cf90b4b61833166b4a068e79 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.103 2000/06/19 23:40:48 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.104 2000/06/28 03:32:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -917,10 +917,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
    /* ----------------
     *  allocate storage for the relation descriptor,
     *  initialize relation->rd_rel and get the access method id.
-    *  The storage is allocated in memory context CacheCxt.
+    *  The storage is allocated in memory context CacheMemoryContext.
     * ----------------
     */
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    relation = AllocateRelationDesc(oldrelation, natts, relp);
    relam = relation->rd_rel->relam;
 
@@ -1383,7 +1383,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
    if (relation->rd_isnailed)
        return;
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /*
     * Remove relation from hash tables
@@ -1574,7 +1574,7 @@ RelationForgetRelation(Oid rid)
            List       *curr;
            List       *prev = NIL;
 
-           oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+           oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
            foreach(curr, newlyCreatedRelns)
            {
@@ -1731,10 +1731,7 @@ RelationRegisterRelation(Relation relation)
 {
    MemoryContext oldcxt;
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
-
-   if (oldcxt != (MemoryContext) CacheCxt)
-       elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    RelationInitLockInfo(relation);
 
@@ -1769,7 +1766,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
    if (newlyCreatedRelns == NULL)
        return;
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    while (newlyCreatedRelns)
    {
@@ -1822,10 +1819,10 @@ RelationInitialize(void)
     *  switch to cache memory context
     * ----------------
     */
-   if (!CacheCxt)
-       CacheCxt = CreateGlobalMemory("Cache");
+   if (!CacheMemoryContext)
+       CreateCacheMemoryContext();
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    /* ----------------
     *  create global caches
@@ -2186,7 +2183,7 @@ RelationGetIndexList(Relation relation)
    heap_close(indrel, AccessShareLock);
 
    /* Now save a copy of the completed list in the relcache entry. */
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    relation->rd_indexlist = listCopy(result);
    relation->rd_indexfound = true;
    MemoryContextSwitchTo(oldcxt);
index d09e35336e1a5b8bb8c247703d6f0c08eb66c2cf..20c94ac57b6ec7630ac3a6933a85cc05b91cafdb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.24 2000/06/20 06:41:12 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.25 2000/06/28 03:32:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,7 +67,7 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
    MemoryContext oldcxt;
    TempTable  *temp_rel;
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    temp_rel = (TempTable *) palloc(sizeof(TempTable));
    temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
@@ -135,7 +135,7 @@ remove_temp_relation(Oid relid)
    List       *l,
               *prev;
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    prev = NIL;
    l = temp_rels;
@@ -185,7 +185,7 @@ invalidate_temp_relations(void)
    List       *l,
               *prev;
 
-   oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+   oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
    prev = NIL;
    l = temp_rels;
index 5b05b81a183752db514582dcc65c8095feaaca0b..da8d80763a72f0426ba01120a45f124fdeef91c8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.60 2000/06/04 15:06:29 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.61 2000/06/28 03:32:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,7 +27,7 @@
 #include 
 #include 
 #ifdef ENABLE_SYSLOG
-# include 
+#include 
 #endif
 
 #include "libpq/libpq.h"
@@ -89,10 +89,9 @@ static int   ElogDebugIndentLevel = 0;
  *--------------------
  */
 void
-elog(int lev, const char *fmt,...)
+elog(int lev, const char *fmt, ...)
 {
    va_list     ap;
-
    /*
     * The expanded format and final output message are dynamically
     * allocated if necessary, but not if they fit in the "reasonable
@@ -101,12 +100,21 @@ elog(int lev, const char *fmt,...)
     * working (since memory-clobber errors often take out malloc first).
     * Don't make these buffers unreasonably large though, on pain of
     * having to chase a bug with no error message.
+    *
+    * Note that we use malloc() not palloc() because we want to retain
+    * control if we run out of memory.  palloc() would recursively call
+    * elog(ERROR), which would be all right except if we are working on a
+    * FATAL or REALLYFATAL error.  We'd lose track of the fatal condition
+    * and report a mere ERROR to outer loop, which would be a Bad Thing.
+    * So, we substitute an appropriate message in-place, without downgrading
+    * the level if it's above ERROR.
     */
    char        fmt_fixedbuf[128];
    char        msg_fixedbuf[256];
    char       *fmt_buf = fmt_fixedbuf;
    char       *msg_buf = msg_fixedbuf;
-
+   /* this buffer is only used for strange values of lev: */
+   char        prefix_buf[32];
    /* this buffer is only used if errno has a bogus value: */
    char        errorstr_buf[32];
    const char *errorstr;
@@ -115,7 +123,6 @@ elog(int lev, const char *fmt,...)
    char       *bp;
    int         indent = 0;
    int         space_needed;
-
    int         len;
    /* size of the prefix needed for timestamp and pid, if enabled */
    size_t      timestamp_size;
@@ -123,6 +130,15 @@ elog(int lev, const char *fmt,...)
    if (lev <= DEBUG && Debugfile < 0)
        return;                 /* ignore debug msgs if noplace to send */
 
+   /* save errno string for %m */
+   if (errno < sys_nerr && errno >= 0)
+       errorstr = strerror(errno);
+   else
+   {
+       sprintf(errorstr_buf, "error %d", errno);
+       errorstr = errorstr_buf;
+   }
+
    if (lev == ERROR || lev == FATAL)
    {
        /* this is probably redundant... */
@@ -156,21 +172,11 @@ elog(int lev, const char *fmt,...)
            prefix = "ERROR:  ";
            break;
        default:
-           /* temporarily use msg buf for prefix */
-           sprintf(msg_fixedbuf, "FATAL %d:  ", lev);
-           prefix = msg_fixedbuf;
+           sprintf(prefix_buf, "FATAL %d:  ", lev);
+           prefix = prefix_buf;
            break;
    }
 
-   /* get errno string for %m */
-   if (errno < sys_nerr && errno >= 0)
-       errorstr = strerror(errno);
-   else
-   {
-       sprintf(errorstr_buf, "error %d", errno);
-       errorstr = errorstr_buf;
-   }
-
    timestamp_size = 0;
    if (Log_timestamp)
        timestamp_size += TIMESTAMP_SIZE;
@@ -190,9 +196,13 @@ elog(int lev, const char *fmt,...)
        fmt_buf = (char *) malloc(space_needed);
        if (fmt_buf == NULL)
        {
-           /* We're up against it, convert to fatal out-of-memory error */
+           /* We're up against it, convert to out-of-memory error */
            fmt_buf = fmt_fixedbuf;
-           lev = REALLYFATAL;
+           if (lev < FATAL)
+           {
+               lev = ERROR;
+               prefix = "ERROR:  ";
+           }
            fmt = "elog: out of memory";        /* this must fit in
                                                 * fmt_fixedbuf! */
        }
@@ -281,15 +291,20 @@ elog(int lev, const char *fmt,...)
        msg_buf = (char *) malloc(space_needed);
        if (msg_buf == NULL)
        {
-           /* We're up against it, convert to fatal out-of-memory error */
+           /* We're up against it, convert to out-of-memory error */
            msg_buf = msg_fixedbuf;
-           lev = REALLYFATAL;
+           if (lev < FATAL)
+           {
+               lev = ERROR;
+               prefix = "ERROR:  ";
+           }
            msg_buf[0] = '\0';
            if (Log_timestamp)
                strcat(msg_buf, print_timestamp());
            if (Log_pid)
                strcat(msg_buf, print_pid());
-           strcat(msg_buf, "FATAL:  elog: out of memory");
+           strcat(msg_buf, prefix);
+           strcat(msg_buf, "elog: out of memory");
            break;
        }
    }
index ca9b01a8c4a8a1fe12b7cca7f70130cec85c2b7f..baa89be7bb8c8e89878702a5d224e70c628b223d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.42 2000/06/15 04:10:29 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.43 2000/06/28 03:32:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -134,7 +134,7 @@ load_external_function(char *filename, char *funcname)
        file_scanner = (DynamicFileList *)
            malloc(sizeof(DynamicFileList) + strlen(filename));
        if (file_scanner == NULL)
-           elog(FATAL, "Out of memory in load_external_function");
+           elog(ERROR, "Out of memory in load_external_function");
 
        MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
        strcpy(file_scanner->filename, filename);
index 93707fcba91cbd30510a64fca58efb04895495c9..9646a7c5504424670f606218953fa10cb6133489 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.31 2000/04/12 17:16:00 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.32 2000/06/28 03:32:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,8 +56,7 @@
 /*
  * Private function prototypes
  */
-static long *DynaHashAlloc(unsigned int size);
-static void DynaHashFree(Pointer ptr);
+static void *DynaHashAlloc(Size size);
 static uint32 call_hash(HTAB *hashp, char *k);
 static SEG_OFFSET seg_alloc(HTAB *hashp);
 static int bucket_alloc(HTAB *hashp);
@@ -66,9 +65,7 @@ static int    expand_table(HTAB *hashp);
 static int hdefault(HTAB *hashp);
 static int init_htab(HTAB *hashp, int nelem);
 
-typedef long *((*dhalloc_ptr) ());
 
-#ifndef FRONTEND
 /* ----------------
  * memory allocation routines
  *
@@ -84,34 +81,24 @@ typedef long *((*dhalloc_ptr) ());
  *    do the latter -cim 1/19/91
  * ----------------
  */
-GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
+static MemoryContext DynaHashCxt = NULL;
 
-static long *
-DynaHashAlloc(unsigned int size)
+static void *
+DynaHashAlloc(Size size)
 {
    if (!DynaHashCxt)
-       DynaHashCxt = CreateGlobalMemory("DynaHash");
+       DynaHashCxt = AllocSetContextCreate(TopMemoryContext,
+                                           "DynaHash",
+                                           ALLOCSET_DEFAULT_MINSIZE,
+                                           ALLOCSET_DEFAULT_INITSIZE,
+                                           ALLOCSET_DEFAULT_MAXSIZE);
 
-   return (long *)
-       MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
-}
-
-static void
-DynaHashFree(Pointer ptr)
-{
-   MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
+   return MemoryContextAlloc(DynaHashCxt, size);
 }
 
 #define MEM_ALLOC      DynaHashAlloc
-#define MEM_FREE       DynaHashFree
-
-#else                          /* FRONTEND */
-
-#define MEM_ALLOC      palloc
 #define MEM_FREE       pfree
 
-#endif  /* FRONTEND */
-
 
 /*
  * pointer access macros.  Shared memory implementation cannot
@@ -147,7 +134,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
    HTAB       *hashp;
 
 
-   hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
+   hashp = (HTAB *) MEM_ALLOC(sizeof(HTAB));
    MemSet(hashp, 0, sizeof(HTAB));
 
    if (flags & HASH_FUNCTION)
@@ -181,7 +168,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
        /* setup hash table defaults */
 
        hashp->hctl = NULL;
-       hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
+       hashp->alloc = MEM_ALLOC;
        hashp->dir = NULL;
        hashp->segbase = NULL;
 
@@ -189,7 +176,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
 
    if (!hashp->hctl)
    {
-       hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
+       hashp->hctl = (HHDR *) hashp->alloc(sizeof(HHDR));
        if (!hashp->hctl)
            return 0;
    }
@@ -318,7 +305,8 @@ init_htab(HTAB *hashp, int nelem)
    /* Allocate a directory */
    if (!(hashp->dir))
    {
-       hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
+       hashp->dir = (SEG_OFFSET *)
+           hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
        if (!hashp->dir)
            return -1;
    }
@@ -445,7 +433,7 @@ hash_destroy(HTAB *hashp)
        /* cannot destroy a shared memory hash table */
        Assert(!hashp->segbase);
        /* allocation method must be one we know how to free, too */
-       Assert(hashp->alloc == (dhalloc_ptr) MEM_ALLOC);
+       Assert(hashp->alloc == MEM_ALLOC);
 
        hash_stats("destroy", hashp);
 
@@ -885,7 +873,7 @@ dir_realloc(HTAB *hashp)
    new_dirsize = new_dsize * sizeof(SEG_OFFSET);
 
    old_p = (char *) hashp->dir;
-   p = (char *) hashp->alloc((unsigned long) new_dirsize);
+   p = (char *) hashp->alloc((Size) new_dirsize);
 
    if (p != NULL)
    {
@@ -906,8 +894,7 @@ seg_alloc(HTAB *hashp)
    SEGMENT     segp;
    SEG_OFFSET  segOffset;
 
-   segp = (SEGMENT) hashp->alloc((unsigned long)
-                             sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
+   segp = (SEGMENT) hashp->alloc(sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
 
    if (!segp)
        return 0;
@@ -937,8 +924,7 @@ bucket_alloc(HTAB *hashp)
    /* make sure its aligned correctly */
    bucketSize = MAXALIGN(bucketSize);
 
-   tmpBucket = (ELEMENT *)
-       hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
+   tmpBucket = (ELEMENT *) hashp->alloc(BUCKET_ALLOC_INCR * bucketSize);
 
    if (!tmpBucket)
        return 0;
index 60ee275c6414cbc5aa945f6f523a7a2dd86d8157..9e3e3e9d42b6d363305205730c2c7a4ecd50b71b 100644 (file)
@@ -4,14 +4,14 @@
 #    Makefile for utils/init
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.13 2000/05/29 05:45:32 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.14 2000/06/28 03:32:43 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
 SRCDIR = ../../..
 include ../../../Makefile.global
 
-OBJS = enbl.o findbe.o globals.o miscinit.o postinit.o
+OBJS = findbe.o globals.o miscinit.o postinit.o
 
 all: SUBSYS.o
 
@@ -27,4 +27,3 @@ clean:
 ifeq (depend,$(wildcard depend))
 include depend
 endif
-
diff --git a/src/backend/utils/init/enbl.c b/src/backend/utils/init/enbl.c
deleted file mode 100644 (file)
index 137653e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * enbl.c
- *   POSTGRES module enable and disable support code.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/enbl.c,v 1.10 2000/01/26 05:57:26 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-#include "utils/module.h"
-
-/*
- * BypassEnable
- *     False iff enable/disable processing is required given on and "*countP."
- *
- * Note:
- *     As a side-effect, *countP is modified.  It should be 0 initially.
- *
- * Exceptions:
- *     BadState if called with pointer to value 0 and false.
- *     BadArg if "countP" is invalid pointer.
- *     BadArg if on is invalid.
- */
-bool
-BypassEnable(int *enableCountInOutP, bool on)
-{
-   AssertArg(PointerIsValid(enableCountInOutP));
-   AssertArg(BoolIsValid(on));
-
-   if (on)
-   {
-       *enableCountInOutP += 1;
-       return (bool) (*enableCountInOutP >= 2);
-   }
-
-   Assert(*enableCountInOutP >= 1);
-
-   *enableCountInOutP -= 1;
-
-   return (bool) (*enableCountInOutP >= 1);
-}
index 51cab6f0e8e85f1ab1efad8ffbd262bc5cff6c11..f2a5864666ce359d38798f8a980e227c842b6fb9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.59 2000/05/30 00:49:56 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.60 2000/06/28 03:32:43 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -40,8 +40,6 @@
 #include "mb/pg_wchar.h"
 #endif
 
-void       BaseInit(void);
-
 static void ReverifyMyDatabase(const char *name);
 static void InitCommunication(void);
 
@@ -222,8 +220,6 @@ InitCommunication()
  *     Be very careful with the order of calls in the InitPostgres function.
  * --------------------------------
  */
-extern int NBuffers;
-
 int            lockingOff = 0;     /* backend -L switch */
 
 /*
@@ -405,21 +401,6 @@ InitPostgres(const char *dbname)
 void
 BaseInit(void)
 {
-
-   /*
-    * Turn on the exception handler. Note: we cannot use elog, Assert,
-    * AssertState, etc. until after exception handling is on.
-    */
-   EnableExceptionHandling(true);
-
-   /*
-    * Memory system initialization - we may call palloc after
-    * EnableMemoryContext()).  Note that EnableMemoryContext() must
-    * happen before EnablePortalManager().
-    */
-   EnableMemoryContext(true);  /* initializes the "top context" */
-   EnablePortalManager(true);  /* memory for portal/transaction stuff */
-
    /*
     * Attach to shared memory and semaphores, and initialize our
     * input/output/debugging file descriptors.
@@ -427,4 +408,6 @@ BaseInit(void)
    InitCommunication();
    DebugFileOpen();
    smgrinit();
+
+   EnablePortalManager();      /* memory for portal/transaction stuff */
 }
index 7ee42f0e336f155fd008192da80c3545487f87e7..af7f5623b547396c5587ce41ddf489a5d83ff0fd 100644 (file)
@@ -6,7 +6,7 @@
  * WIN1250 client encoding support contributed by Pavel Behal
  * SJIS UDC (NEC selection IBM kanji) support contributed by Eiji Tokuya
  *
- * $Id: conv.c,v 1.15 2000/05/20 13:12:26 ishii Exp $
+ * $Id: conv.c,v 1.16 2000/06/28 03:32:45 tgl Exp $
  *
  *
  */
@@ -1521,7 +1521,8 @@ pg_encoding_conv_tbl pg_conv_tbl[] = {
 };
 
 #ifdef DEBUGMAIN
-#include "utils/mcxt.h"
+#include "postgres.h"
+#include "utils/memutils.h"
 /*
  * testing for sjis2mic() and mic2sjis()
  */
@@ -1565,21 +1566,23 @@ main()
 void
 elog(int lev, const char *fmt,...)
 {
-};
+}
+
 MemoryContext CurrentMemoryContext;
-Pointer
+
+void *
 MemoryContextAlloc(MemoryContext context, Size size)
 {
-};
-Pointer
-MemoryContextRealloc(MemoryContext context,
-                    Pointer pointer,
-                    Size size)
-{
-};
+}
+
 void
-MemoryContextFree(MemoryContext context, Pointer pointer)
+pfree(void *pointer)
 {
-};
+}
+
+void *
+repalloc(void *pointer, Size size)
+{
+}
 
 #endif
index 47698172228bebc7e5a04d1341b8059d37e7e2d0..371f97678141a1d63553c911bd601bbd8fc05c58 100644 (file)
@@ -4,14 +4,14 @@
 #    Makefile for utils/mmgr
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.8 2000/05/29 05:45:40 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.9 2000/06/28 03:32:50 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
 SRCDIR = ../../..
 include ../../../Makefile.global
 
-OBJS = aset.o mcxt.o palloc.o portalmem.o oset.o
+OBJS = aset.o mcxt.o portalmem.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/utils/mmgr/README b/src/backend/utils/mmgr/README
new file mode 100644 (file)
index 0000000..1b82d63
--- /dev/null
@@ -0,0 +1,379 @@
+Proposal for memory allocation fixes, take 2       21-Jun-2000
+--------------------------------------------
+
+We know that Postgres has serious problems with memory leakage during
+large queries that process a lot of pass-by-reference data.  There is
+no provision for recycling memory until end of query.  This needs to be
+fixed, even more so with the advent of TOAST which will allow very large
+chunks of data to be passed around in the system.  So, here is a proposal.
+
+
+Background
+----------
+
+We already do most of our memory allocation in "memory contexts", which
+are usually AllocSets as implemented by backend/utils/mmgr/aset.c.  What
+we need to do is create more contexts and define proper rules about when
+they can be freed.
+
+The basic operations on a memory context are:
+
+* create a context
+
+* allocate a chunk of memory within a context (equivalent of standard
+  C library's malloc())
+
+* delete a context (including freeing all the memory allocated therein)
+
+* reset a context (free all memory allocated in the context, but not the
+  context object itself)
+
+Given a chunk of memory previously allocated from a context, one can
+free it or reallocate it larger or smaller (corresponding to standard
+library's free() and realloc() routines).  These operations return memory
+to or get more memory from the same context the chunk was originally
+allocated in.
+
+At all times there is a "current" context denoted by the
+CurrentMemoryContext global variable.  The backend macro palloc()
+implicitly allocates space in that context.  The MemoryContextSwitchTo()
+operation selects a new current context (and returns the previous context,
+so that the caller can restore the previous context before exiting).
+
+The main advantage of memory contexts over plain use of malloc/free is
+that the entire contents of a memory context can be freed easily, without
+having to request freeing of each individual chunk within it.  This is
+both faster and more reliable than per-chunk bookkeeping.  We already use
+this fact to clean up at transaction end: by resetting all the active
+contexts, we reclaim all memory.  What we need are additional contexts
+that can be reset or deleted at strategic times within a query, such as
+after each tuple.
+
+
+pfree/repalloc no longer depend on CurrentMemoryContext
+-------------------------------------------------------
+
+In this proposal, pfree() and repalloc() can be applied to any chunk
+whether it belongs to CurrentMemoryContext or not --- the chunk's owning
+context will be invoked to handle the operation, regardless.  This is a
+change from the old requirement that CurrentMemoryContext must be set
+to the same context the memory was allocated from before one can use
+pfree() or repalloc().  The old coding requirement is obviously fairly
+error-prone, and will become more so the more context-switching we do;
+so I think it's essential to use CurrentMemoryContext only for palloc.
+We can avoid needing it for pfree/repalloc by putting restrictions on
+context managers as discussed below.
+
+We could even consider getting rid of CurrentMemoryContext entirely,
+instead requiring the target memory context for allocation to be specified
+explicitly.  But I think that would be too much notational overhead ---
+we'd have to pass an apppropriate memory context to called routines in
+many places.  For example, the copyObject routines would need to be passed
+a context, as would function execution routines that return a
+pass-by-reference datatype.  And what of routines that temporarily
+allocate space internally, but don't return it to their caller?  We
+certainly don't want to clutter every call in the system with "here is
+a context to use for any temporary memory allocation you might want to
+do".  So there'd still need to be a global variable specifying a suitable
+temporary-allocation context.  That might as well be CurrentMemoryContext.
+
+
+Additions to the memory-context mechanism
+-----------------------------------------
+
+If we are going to have more contexts, we need more mechanism for keeping
+track of them; else we risk leaking whole contexts under error conditions.
+
+We can do this by creating trees of "parent" and "child" contexts.  When
+creating a memory context, the new context can be specified to be a child
+of some existing context.  A context can have many children, but only one
+parent.  In this way the contexts form a forest (not necessarily a single
+tree, since there could be more than one top-level context).
+
+We then say that resetting or deleting any particular context resets or
+deletes all its direct and indirect children as well.  This feature allows
+us to manage a lot of contexts without fear that some will be leaked; we
+only need to keep track of one top-level context that we are going to
+delete at transaction end, and make sure that any shorter-lived contexts
+we create are descendants of that context.  Since the tree can have
+multiple levels, we can deal easily with nested lifetimes of storage,
+such as per-transaction, per-statement, per-scan, per-tuple.  Storage
+lifetimes that only partially overlap can be handled by allocating
+from different trees of the context forest (there are some examples
+in the next section).
+
+For convenience we will also want operations like "reset/delete all
+children of a given context, but don't reset or delete that context
+itself".
+
+
+Top-level contexts
+------------------
+
+There will be several top-level contexts --- these contexts have no parent
+and will be referenced by global variables.  At any instant the system may
+contain many additional contexts, but all other contexts should be direct
+or indirect children of one of the top-level contexts to ensure they are
+not leaked in event of an error.  I presently envision these top-level
+contexts:
+
+TopMemoryContext --- allocating here is essentially the same as "malloc",
+because this context will never be reset or deleted.  This is for stuff
+that should live forever, or for stuff that you know you will delete
+at the appropriate time.  An example is fd.c's tables of open files,
+as well as the context management nodes for memory contexts themselves.
+Avoid allocating stuff here unless really necessary, and especially
+avoid running with CurrentMemoryContext pointing here.
+
+PostmasterContext --- this is the postmaster's normal working context.
+After a backend is spawned, it can delete PostmasterContext to free its
+copy of memory the postmaster was using that it doesn't need.  (Anything
+that has to be passed from postmaster to backends will be passed in
+TopMemoryContext.  The postmaster will probably have only TopMemoryContext,
+PostmasterContext, and possibly ErrorContext --- the remaining top-level
+contexts will be set up in each backend during startup.)
+
+CacheMemoryContext --- permanent storage for relcache, catcache, and
+related modules.  This will never be reset or deleted, either, so it's
+not truly necessary to distinguish it from TopMemoryContext.  But it
+seems worthwhile to maintain the distinction for debugging purposes.
+(Note: CacheMemoryContext may well have child-contexts with shorter
+lifespans.  For example, a child context seems like the best place to
+keep the subsidiary storage associated with a relcache entry; that way
+we can free rule parsetrees and so forth easily, without having to depend
+on constructing a reliable version of freeObject().)
+
+QueryContext --- this is where the storage holding a received query string
+is kept, as well as storage that should live as long as the query string,
+notably the parsetree constructed from it.  This context will be reset at
+the top of each cycle of the outer loop of PostgresMain, thereby freeing
+the old query and parsetree.  We must keep this separate from
+TopTransactionContext because a query string might need to live either a
+longer or shorter time than a transaction, depending on whether it
+contains begin/end commands or not.  (This'll also fix the nasty bug that
+"vacuum; anything else" crashes if submitted as a single query string,
+because vacuum's xact commit frees the memory holding the parsetree...)
+
+TopTransactionContext --- this holds everything that lives until end of
+transaction (longer than one statement within a transaction!).  An example
+of what has to be here is the list of pending NOTIFY messages to be sent
+at xact commit.  This context will be reset, and all its children deleted,
+at conclusion of each transaction cycle.  Note: presently I envision that
+this context will NOT be cleared immediately upon error; its contents
+will survive anyway until the transaction block is exited by
+COMMIT/ROLLBACK.  This seems appropriate since we want to move in the
+direction of allowing a transaction to continue processing after an error.
+
+TransactionCommandContext --- this is really a child of
+TopTransactionContext, not a top-level context, but we'll probably store a
+link to it in a global variable anyway for convenience.  All the memory
+allocated during planning and execution lives here or in a child context.
+This context is deleted at statement completion, whether normal completion
+or error abort.
+
+ErrorContext --- this permanent context will be switched into
+for error recovery processing, and then reset on completion of recovery.
+We'll arrange to have, say, 8K of memory available in it at all times.
+In this way, we can ensure that some memory is available for error
+recovery even if the backend has run out of memory otherwise.  This should
+allow out-of-memory to be treated as a normal ERROR condition, not a FATAL
+error.
+
+If we ever implement nested transactions, there may need to be some
+additional levels of transaction-local contexts between
+TopTransactionContext and TransactionCommandContext, but that's beyond
+the scope of this proposal.
+
+
+Transient contexts during execution
+-----------------------------------
+
+The planner will probably have a transient context in which it stores
+pathnodes; this will allow it to release the bulk of its temporary space
+usage (which can be a lot, for large joins) at completion of planning.
+The completed plan tree will be in TransactionCommandContext.
+
+The executor will have contexts with lifetime similar to plan nodes
+(I'm not sure at the moment whether there's need for one such context
+per plan level, or whether a single context is sufficient).  These
+contexts will hold plan-node-local execution state and related items.
+There will also be a context on each plan level that is reset at the start
+of each tuple processing cycle.  This per-tuple context will be the normal
+CurrentMemoryContext during evaluation of expressions and so forth.  By
+resetting it, we reclaim transient memory that was used during processing
+of the prior tuple.  That should be enough to solve the problem of running
+out of memory on large queries.  We must have a per-tuple context in each
+plan node, and we must reset it at the start of a tuple cycle rather than
+the end, so that each plan node can use results of expression evaluation
+as part of the tuple it returns to its parent node.
+
+By resetting the per-tuple context, we will be able to free memory after
+each tuple is processed, rather than only after the whole plan is
+processed.  This should solve our memory leakage problems pretty well;
+yet we do not need to add very much new bookkeeping logic to do it.
+In particular, we do *not* need to try to keep track of individual values
+palloc'd during expression evaluation.
+
+Note we assume that resetting a context is a cheap operation.  This is
+true already, and we can make it even more true with a little bit of
+tuning in aset.c.
+
+There will be some special cases, such as aggregate functions.  nodeAgg.c
+needs to remember the results of evaluation of aggregate transition
+functions from one tuple cycle to the next, so it can't just discard
+all per-tuple state in each cycle.  The easiest way to handle this seems
+to be to have two per-tuple contexts in an aggregate node, and to
+ping-pong between them, so that at each tuple one is the active allocation
+context and the other holds any results allocated by the prior cycle's
+transition function.
+
+Executor routines that switch the active CurrentMemoryContext may need
+to copy data into their caller's current memory context before returning.
+I think there will be relatively little need for that, because of the
+convention of resetting the per-tuple context at the *start* of an
+execution cycle rather than at its end.  With that rule, an execution
+node can return a tuple that is palloc'd in its per-tuple context, and
+the tuple will remain good until the node is called for another tuple
+or told to end execution.  This is pretty much the same state of affairs
+that exists now, since a scan node can return a direct pointer to a tuple
+in a disk buffer that is only guaranteed to remain good that long.
+
+A more common reason for copying data will be to transfer a result from
+per-tuple context to per-run context; for example, a Unique node will
+save the last distinct tuple value in its per-run context, requiring a
+copy step.  (Actually, Unique could use the same trick with two per-tuple
+contexts as described above for Agg, but there will probably be other
+cases where doing an extra copy step is the right thing.)
+
+Another interesting special case is VACUUM, which needs to allocate
+working space that will survive its forced transaction commits, yet
+be released on error.  Currently it does that through a "portal",
+which is essentially a child context of TopMemoryContext.  While that
+way still works, it's ugly since xact abort needs special processing
+to delete the portal.  Better would be to use a context that's a child
+of QueryContext and hence is certain to go away as part of normal
+processing.  (Eventually we might have an even better solution from
+nested transactions, but this'll do fine for now.)
+
+
+Mechanisms to allow multiple types of contexts
+----------------------------------------------
+
+We may want several different types of memory contexts with different
+allocation policies but similar external behavior.  To handle this,
+memory allocation functions will be accessed via function pointers,
+and we will require all context types to obey the conventions given here.
+(This is not very far different from the existing code.)
+
+A memory context will be represented by an object like
+
+typedef struct MemoryContextData
+{
+    NodeTag        type;           /* identifies exact kind of context */
+    MemoryContextMethods methods;
+    MemoryContextData *parent;     /* NULL if no parent (toplevel context) */
+    MemoryContextData *firstchild; /* head of linked list of children */
+    MemoryContextData *nextchild;  /* next child of same parent */
+    char          *name;           /* context name (just for debugging) */
+} MemoryContextData, *MemoryContext;
+
+This is essentially an abstract superclass, and the "methods" pointer is
+its virtual function table.  Specific memory context types will use
+derived structs having these fields as their first fields.  All the
+contexts of a specific type will have methods pointers that point to the
+same static table of function pointers, which will look like
+
+typedef struct MemoryContextMethodsData
+{
+    Pointer     (*alloc) (MemoryContext c, Size size);
+    void        (*free_p) (Pointer chunk);
+    Pointer     (*realloc) (Pointer chunk, Size newsize);
+    void        (*reset) (MemoryContext c);
+    void        (*delete) (MemoryContext c);
+} MemoryContextMethodsData, *MemoryContextMethods;
+
+Alloc, reset, and delete requests will take a MemoryContext pointer
+as parameter, so they'll have no trouble finding the method pointer
+to call.  Free and realloc are trickier.  To make those work, we will
+require all memory context types to produce allocated chunks that
+are immediately preceded by a standard chunk header, which has the
+layout
+
+typedef struct StandardChunkHeader
+{
+    MemoryContext mycontext;         /* Link to owning context object */
+    Size          size;              /* Allocated size of chunk */
+};
+
+It turns out that the existing aset.c memory context type does this
+already, and probably any other kind of context would need to have the
+same data available to support realloc, so this is not really creating
+any additional overhead.  (Note that if a context type needs more per-
+allocated-chunk information than this, it can make an additional
+nonstandard header that precedes the standard header.  So we're not
+constraining context-type designers very much.)
+
+Given this, the pfree routine will look something like
+
+    StandardChunkHeader * header = 
+        (StandardChunkHeader *) ((char *) p - sizeof(StandardChunkHeader));
+
+    (*header->mycontext->methods->free_p) (p);
+
+We could do it as a macro, but the macro would have to evaluate its
+argument twice, which seems like a bad idea (the current pfree macro
+does not do that).  This is already saving two levels of function call
+compared to the existing code, so I think we're doing fine without
+squeezing out that last little bit ...
+
+
+More control over aset.c behavior
+---------------------------------
+
+Currently, aset.c allocates an 8K block upon the first allocation in
+a context, and doubles that size for each successive block request.
+That's good behavior for a context that might hold *lots* of data, and
+the overhead wasn't bad when we had only a few contexts in existence.
+With dozens if not hundreds of smaller contexts in the system, we will
+want to be able to fine-tune things a little better.
+
+The creator of a context will be able to specify an initial block size
+and a maximum block size.  Selecting smaller values will prevent wastage
+of space in contexts that aren't expected to hold very much (an example is
+the relcache's per-relation contexts).
+
+Also, it will be possible to specify a minimum context size.  If this
+value is greater than zero then a block of that size will be grabbed
+immediately upon context creation, and cleared but not released during
+context resets.  This feature is needed for ErrorContext (see above).
+It is also useful for per-tuple contexts, which will be reset frequently
+and typically will not allocate very much space per tuple cycle.  We can
+save a lot of unnecessary malloc traffic if these contexts hang onto one
+allocation block rather than releasing and reacquiring the block on
+each tuple cycle.
+
+
+Other notes
+-----------
+
+The original version of this proposal suggested that functions returning
+pass-by-reference datatypes should be required to return a value freshly
+palloc'd in their caller's memory context, never a pointer to an input
+value.  I've abandoned that notion since it clearly is prone to error.
+In the current proposal, it is possible to discover which context a
+chunk of memory is allocated in (by checking the required standard chunk
+header), so nodeAgg can determine whether or not it's safe to reset
+its working context; it doesn't have to rely on the transition function
+to do what it's expecting.
+
+It might be that the executor per-run contexts described above should
+be tied directly to executor "EState" nodes, that is, one context per
+EState.  I'm not real clear on the lifespan of EStates or the situations
+where we have just one or more than one, so I'm not sure.  Comments?
+
+It would probably be possible to adapt the existing "portal" memory
+management mechanism to do what we need.  I am instead proposing setting
+up a totally new mechanism, because the portal code strikes me as
+extremely crufty and unwieldy.  It may be that we can eventually remove
+portals entirely, or perhaps reimplement them with this mechanism
+underneath.
index 574b98697d2062194f1c3629d85a595fbf767dc5..e0244ade7836e84bea53e7cfea5e1f071f39fdcf 100644 (file)
@@ -3,12 +3,15 @@
  * aset.c
  *   Allocation set definitions.
  *
+ * AllocSet is our standard implementation of the abstract MemoryContext
+ * type.
+ *
+ *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.27 2000/05/21 02:23:29 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.28 2000/06/28 03:32:50 tgl Exp $
  *
  * NOTE:
  * This is a new (Feb. 05, 1999) implementation of the allocation set
  * AllocSetReset() under the old way.
  *-------------------------------------------------------------------------
  */
+
 #include "postgres.h"
+
 #include "utils/memutils.h"
 
 
-#undef AllocSetReset
-#undef malloc
-#undef free
-#undef realloc
+/*
+ * AllocSetContext is defined in nodes/memnodes.h.
+ */
+typedef AllocSetContext *AllocSet;
+
+/*
+ * AllocPointer
+ *     Aligned pointer which may be a member of an allocation set.
+ */
+typedef void *AllocPointer;
+
+/*
+ * AllocBlock
+ *     An AllocBlock is the unit of memory that is obtained by aset.c
+ *     from malloc().  It contains one or more AllocChunks, which are
+ *     the units requested by palloc() and freed by pfree().  AllocChunks
+ *     cannot be returned to malloc() individually, instead they are put
+ *     on freelists by pfree() and re-used by the next palloc() that has
+ *     a matching request size.
+ *
+ *     AllocBlockData is the header data for a block --- the usable space
+ *     within the block begins at the next alignment boundary.
+ */
+typedef struct AllocBlockData
+{
+   AllocSet    aset;           /* aset that owns this block */
+   AllocBlock  next;           /* next block in aset's blocks list */
+   char       *freeptr;        /* start of free space in this block */
+   char       *endptr;         /* end of space in this block */
+} AllocBlockData;
+
+/*
+ * AllocChunk
+ *     The prefix of each piece of memory in an AllocBlock
+ *
+ * NB: this MUST match StandardChunkHeader as defined by utils/memutils.h.
+ */
+typedef struct AllocChunkData
+{
+   /* aset is the owning aset if allocated, or the freelist link if free */
+   void       *aset;
+   /* size is always the size of the usable space in the chunk */
+   Size        size;
+} AllocChunkData;
 
+/*
+ * AllocPointerIsValid
+ *     True iff pointer is valid allocation pointer.
+ */
+#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
+
+/*
+ * AllocSetIsValid
+ *     True iff set is valid allocation set.
+ */
+#define AllocSetIsValid(set) PointerIsValid(set)
 
 /*--------------------
  * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
 /* Size of largest chunk that we use a fixed size for */
 
 /*--------------------
- * The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
+ * The first block allocated for an allocset has size initBlockSize.
  * Each time we have to allocate another block, we double the block size
- * (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
+ * (if possible, and without exceeding maxBlockSize), so as to reduce
  * the bookkeeping load on malloc().
  *
  * Blocks allocated to hold oversize chunks do not follow this rule, however;
  * AllocSetAlloc has discretion whether to put the request into an existing
  * block or make a single-chunk block.
  *
- * We must have ALLOC_MIN_BLOCK_SIZE > ALLOC_SMALLCHUNK_LIMIT and
+ * We must have initBlockSize > ALLOC_SMALLCHUNK_LIMIT and
  * ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
  *--------------------
  */
 
-#define ALLOC_MIN_BLOCK_SIZE   (8 * 1024)
-#define ALLOC_MAX_BLOCK_SIZE   (8 * 1024 * 1024)
-
 #define ALLOC_BIGCHUNK_LIMIT   (64 * 1024)
 /* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
 
 #define ALLOC_BLOCKHDRSZ   MAXALIGN(sizeof(AllocBlockData))
 #define ALLOC_CHUNKHDRSZ   MAXALIGN(sizeof(AllocChunkData))
 
+/* Min safe value of allocation block size */
+#define ALLOC_MIN_BLOCK_SIZE  \
+   (ALLOC_SMALLCHUNK_LIMIT + ALLOC_CHUNKHDRSZ + ALLOC_BLOCKHDRSZ)
+
 #define AllocPointerGetChunk(ptr)  \
                    ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
 #define AllocChunkGetPointer(chk)  \
 #define AllocPointerGetAset(ptr)   ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
 #define AllocPointerGetSize(ptr)   (AllocPointerGetChunk(ptr)->size)
 
+/*
+ * These functions implement the MemoryContext API for AllocSet contexts.
+ */
+static void *AllocSetAlloc(MemoryContext context, Size size);
+static void AllocSetFree(MemoryContext context, void *pointer);
+static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
+static void AllocSetInit(MemoryContext context);
+static void AllocSetReset(MemoryContext context);
+static void AllocSetDelete(MemoryContext context);
+static void AllocSetStats(MemoryContext context);
+
+/*
+ * This is the virtual function table for AllocSet contexts.
+ */
+static MemoryContextMethods AllocSetMethods = {
+   AllocSetAlloc,
+   AllocSetFree,
+   AllocSetRealloc,
+   AllocSetInit,
+   AllocSetReset,
+   AllocSetDelete,
+   AllocSetStats
+};
 
 
 /* ----------
@@ -127,92 +207,182 @@ AllocSetFreeIndex(Size size)
  * Public routines
  */
 
+
 /*
- * AllocSetInit
- *     Initializes given allocation set.
- *
- * Note:
- *     The semantics of the mode are explained above.  Limit is ignored
- *     for dynamic and static modes.
+ * AllocSetContextCreate
+ *     Create a new AllocSet context.
  *
- * Exceptions:
- *     BadArg if set is invalid pointer.
- *     BadArg if mode is invalid.
+ * parent: parent context, or NULL if top-level context
+ * name: name of context (for debugging --- string will be copied)
+ * minContextSize: minimum context size
+ * initBlockSize: initial allocation block size
+ * maxBlockSize: maximum allocation block size
  */
-void
-AllocSetInit(AllocSet set, AllocMode mode, Size limit)
+MemoryContext
+AllocSetContextCreate(MemoryContext parent,
+                     const char *name,
+                     Size minContextSize,
+                     Size initBlockSize,
+                     Size maxBlockSize)
 {
-   AssertArg(PointerIsValid(set));
-   AssertArg((int) DynamicAllocMode <= (int) mode);
-   AssertArg((int) mode <= (int) BoundedAllocMode);
+   AllocSet    context;
+
+   /* Do the type-independent part of context creation */
+   context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
+                                            sizeof(AllocSetContext),
+                                            &AllocSetMethods,
+                                            parent,
+                                            name);
+   /*
+    * Make sure alloc parameters are safe, and save them
+    */
+   initBlockSize = MAXALIGN(initBlockSize);
+   if (initBlockSize < ALLOC_MIN_BLOCK_SIZE)
+       initBlockSize = ALLOC_MIN_BLOCK_SIZE;
+   maxBlockSize = MAXALIGN(maxBlockSize);
+   if (maxBlockSize < initBlockSize)
+       maxBlockSize = initBlockSize;
+   context->initBlockSize = initBlockSize;
+   context->maxBlockSize = maxBlockSize;
 
    /*
-    * XXX mode is currently ignored and treated as DynamicAllocMode. XXX
-    * limit is also ignored.  This affects this whole file.
+    * Grab always-allocated space, if requested
     */
+   if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)
+   {
+       Size        blksize = MAXALIGN(minContextSize);
+       AllocBlock  block;
 
-   memset(set, 0, sizeof(AllocSetData));
+       block = (AllocBlock) malloc(blksize);
+       if (block == NULL)
+           elog(ERROR, "Memory exhausted in AllocSetContextCreate()");
+       block->aset = context;
+       block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
+       block->endptr = ((char *) block) + blksize;
+       block->next = context->blocks;
+       context->blocks = block;
+       /* Mark block as not to be released at reset time */
+       context->keeper = block;
+   }
+
+   return (MemoryContext) context;
 }
 
+/*
+ * AllocSetInit
+ *     Context-type-specific initialization routine.
+ *
+ * This is called by MemoryContextCreate() after setting up the
+ * generic MemoryContext fields and before linking the new context
+ * into the context tree.  We must do whatever is needed to make the
+ * new context minimally valid for deletion.  We must *not* risk
+ * failure --- thus, for example, allocating more memory is not cool.
+ * (AllocSetContextCreate can allocate memory when it gets control
+ * back, however.)
+ */
+static void
+AllocSetInit(MemoryContext context)
+{
+   /*
+    * Since MemoryContextCreate already zeroed the context node,
+    * we don't have to do anything here: it's already OK.
+    */
+}
 
 /*
  * AllocSetReset
  *     Frees all memory which is allocated in the given set.
  *
- * Exceptions:
- *     BadArg if set is invalid.
+ * 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.
  */
-void
-AllocSetReset(AllocSet set)
+static void
+AllocSetReset(MemoryContext context)
 {
+   AllocSet    set = (AllocSet) context;
    AllocBlock  block = set->blocks;
-   AllocBlock  next;
 
    AssertArg(AllocSetIsValid(set));
 
    while (block != NULL)
    {
-       next = block->next;
+       AllocBlock  next = block->next;
+
+       if (block == set->keeper)
+       {
+           /* Reset the block, but don't return it to malloc */
+           block->next = NULL;
+           block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
 #ifdef CLOBBER_FREED_MEMORY
-       /* Wipe freed memory for debugging purposes */
-       memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+           /* Wipe freed memory for debugging purposes */
+           memset(block->freeptr, 0x7F,
+                  ((char *) block->endptr) - ((char *) block->freeptr));
 #endif
-       free(block);
+       }
+       else
+       {
+           /* Normal case, release the block */
+#ifdef CLOBBER_FREED_MEMORY
+           /* Wipe freed memory for debugging purposes */
+           memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+#endif
+           free(block);
+       }
        block = next;
    }
 
-   memset(set, 0, sizeof(AllocSetData));
+   /* Now blocks list is either empty or just the keeper block */
+   set->blocks = set->keeper;
+   /* Clear chunk freelists in any case */
+   MemSet(set->freelist, 0, sizeof(set->freelist));
 }
 
 /*
- * AllocSetContains
- *     True iff allocation set contains given allocation element.
+ * AllocSetDelete
+ *     Frees all memory which is allocated in the given set,
+ *     in preparation for deletion of the set.
  *
- * Exceptions:
- *     BadArg if set is invalid.
- *     BadArg if pointer is invalid.
+ * Unlike AllocSetReset, this *must* free all resources of the set.
+ * But note we are not responsible for deleting the context node itself.
  */
-bool
-AllocSetContains(AllocSet set, AllocPointer pointer)
+static void
+AllocSetDelete(MemoryContext context)
 {
+   AllocSet    set = (AllocSet) context;
+   AllocBlock  block = set->blocks;
+
    AssertArg(AllocSetIsValid(set));
-   AssertArg(AllocPointerIsValid(pointer));
 
-   return (AllocPointerGetAset(pointer) == set);
+   while (block != NULL)
+   {
+       AllocBlock  next = block->next;
+
+#ifdef CLOBBER_FREED_MEMORY
+       /* Wipe freed memory for debugging purposes */
+       memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+#endif
+       free(block);
+       block = next;
+   }
+
+   /* Make it look empty, just in case... */
+   set->blocks = NULL;
+   MemSet(set->freelist, 0, sizeof(set->freelist));
+   set->keeper = NULL;
 }
 
 /*
  * AllocSetAlloc
  *     Returns pointer to allocated memory of given size; memory is added
  *     to the set.
- *
- * Exceptions:
- *     BadArg if set is invalid.
- *     MemoryExhausted if allocation fails.
  */
-AllocPointer
-AllocSetAlloc(AllocSet set, Size size)
+static void *
+AllocSetAlloc(MemoryContext context, Size size)
 {
+   AllocSet    set = (AllocSet) context;
    AllocBlock  block;
    AllocChunk  chunk;
    AllocChunk  priorfree = NULL;
@@ -225,7 +395,6 @@ AllocSetAlloc(AllocSet set, Size size)
    /*
     * Lookup in the corresponding free list if there is a free chunk we
     * could reuse
-    *
     */
    fidx = AllocSetFreeIndex(size);
    for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
@@ -238,7 +407,6 @@ AllocSetAlloc(AllocSet set, Size size)
    /*
     * If one is found, remove it from the free list, make it again a
     * member of the alloc set and return its data address.
-    *
     */
    if (chunk != NULL)
    {
@@ -284,7 +452,7 @@ AllocSetAlloc(AllocSet set, Size size)
        blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
        block = (AllocBlock) malloc(blksize);
        if (block == NULL)
-           elog(FATAL, "Memory exhausted in AllocSetAlloc()");
+           elog(ERROR, "Memory exhausted in AllocSetAlloc()");
        block->aset = set;
        block->freeptr = block->endptr = ((char *) block) + blksize;
 
@@ -317,7 +485,7 @@ AllocSetAlloc(AllocSet set, Size size)
    {
        if (set->blocks == NULL)
        {
-           blksize = ALLOC_MIN_BLOCK_SIZE;
+           blksize = set->initBlockSize;
            block = (AllocBlock) malloc(blksize);
        }
        else
@@ -327,15 +495,18 @@ AllocSetAlloc(AllocSet set, Size size)
 
            /*
             * Special case: if very first allocation was for a large
-            * chunk, could have a funny-sized top block.  Do something
-            * reasonable.
+            * chunk (or we have a small "keeper" block), could have an
+            * undersized top block.  Do something reasonable.
             */
-           if (blksize < ALLOC_MIN_BLOCK_SIZE)
-               blksize = ALLOC_MIN_BLOCK_SIZE;
-           /* Crank it up, but not past max */
-           blksize <<= 1;
-           if (blksize > ALLOC_MAX_BLOCK_SIZE)
-               blksize = ALLOC_MAX_BLOCK_SIZE;
+           if (blksize < set->initBlockSize)
+               blksize = set->initBlockSize;
+           else
+           {
+               /* Crank it up, but not past max */
+               blksize <<= 1;
+               if (blksize > set->maxBlockSize)
+                   blksize = set->maxBlockSize;
+           }
            /* Try to allocate it */
            block = (AllocBlock) malloc(blksize);
 
@@ -352,7 +523,7 @@ AllocSetAlloc(AllocSet set, Size size)
        }
 
        if (block == NULL)
-           elog(FATAL, "Memory exhausted in AllocSetAlloc()");
+           elog(ERROR, "Memory exhausted in AllocSetAlloc()");
        block->aset = set;
        block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
        block->endptr = ((char *) block) + blksize;
@@ -376,22 +547,12 @@ AllocSetAlloc(AllocSet set, Size size)
 /*
  * AllocSetFree
  *     Frees allocated memory; memory is removed from the set.
- *
- * Exceptions:
- *     BadArg if set is invalid.
- *     BadArg if pointer is invalid.
- *     BadArg if pointer is not member of set.
  */
-void
-AllocSetFree(AllocSet set, AllocPointer pointer)
+static void
+AllocSetFree(MemoryContext context, void *pointer)
 {
-   AllocChunk  chunk;
-
-   /* AssertArg(AllocSetIsValid(set)); */
-   /* AssertArg(AllocPointerIsValid(pointer)); */
-   AssertArg(AllocSetContains(set, pointer));
-
-   chunk = AllocPointerGetChunk(pointer);
+   AllocSet    set = (AllocSet) context;
+   AllocChunk  chunk = AllocPointerGetChunk(pointer);
 
 #ifdef CLOBBER_FREED_MEMORY
    /* Wipe freed memory for debugging purposes */
@@ -446,24 +607,15 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
  *     Returns new pointer to allocated memory of given size; this memory
  *     is added to the set.  Memory associated with given pointer is copied
  *     into the new memory, and the old memory is freed.
- *
- * Exceptions:
- *     BadArg if set is invalid.
- *     BadArg if pointer is invalid.
- *     BadArg if pointer is not member of set.
- *     MemoryExhausted if allocation fails.
  */
-AllocPointer
-AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
+static void *
+AllocSetRealloc(MemoryContext context, void *pointer, Size size)
 {
+   AllocSet    set = (AllocSet) context;
    Size        oldsize;
 
-   /* AssertArg(AllocSetIsValid(set)); */
-   /* AssertArg(AllocPointerIsValid(pointer)); */
-   AssertArg(AllocSetContains(set, pointer));
-
    /*
-    * Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
+    * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
     * allocated area already is >= the new size.  (In particular, we
     * always fall out here if the requested size is a decrease.)
     */
@@ -503,7 +655,7 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
        blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
        block = (AllocBlock) realloc(block, blksize);
        if (block == NULL)
-           elog(FATAL, "Memory exhausted in AllocSetReAlloc()");
+           elog(ERROR, "Memory exhausted in AllocSetReAlloc()");
        block->freeptr = block->endptr = ((char *) block) + blksize;
 
        /* Update pointers since block has likely been moved */
@@ -520,35 +672,26 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
        /* Normal small-chunk case: just do it by brute force. */
 
        /* allocate new chunk */
-       AllocPointer newPointer = AllocSetAlloc(set, size);
+       AllocPointer newPointer = AllocSetAlloc((MemoryContext) set, size);
 
        /* transfer existing data (certain to fit) */
        memcpy(newPointer, pointer, oldsize);
 
        /* free old chunk */
-       AllocSetFree(set, pointer);
+       AllocSetFree((MemoryContext) set, pointer);
 
        return newPointer;
    }
 }
 
-/*
- * AllocSetDump
- *     Displays allocated set.
- */
-void
-AllocSetDump(AllocSet set)
-{
-   elog(DEBUG, "Currently unable to dump AllocSet");
-}
-
 /*
  * AllocSetStats
  *     Displays stats about memory consumption of an allocset.
  */
-void
-AllocSetStats(AllocSet set, const char *ident)
+static void
+AllocSetStats(MemoryContext context)
 {
+   AllocSet    set = (AllocSet) context;
    long        nblocks = 0;
    long        nchunks = 0;
    long        totalspace = 0;
@@ -557,8 +700,6 @@ AllocSetStats(AllocSet set, const char *ident)
    AllocChunk  chunk;
    int         fidx;
 
-   AssertArg(AllocSetIsValid(set));
-
    for (block = set->blocks; block != NULL; block = block->next)
    {
        nblocks++;
@@ -576,6 +717,6 @@ AllocSetStats(AllocSet set, const char *ident)
    }
    fprintf(stderr,
            "%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n",
-           ident, totalspace, nblocks, freespace, nchunks,
+           set->header.name, totalspace, nblocks, freespace, nchunks,
            totalspace - freespace);
 }
index 5a3be6700e679b4ba7a37edbe5b8e114f845a8cd..71877c4e62a5edb080dfd35341dfbdbb0fce83d2 100644 (file)
@@ -1,14 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * mcxt.c
- *   POSTGRES memory context code.
+ *   POSTGRES memory context management code.
+ *
+ * This module handles context management operations that are independent
+ * of the particular kind of context being operated on.  It calls
+ * context-type-specific operations via the function pointers in a
+ * context's MemoryContextMethods struct.
+ *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.21 2000/05/21 02:23:29 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.22 2000/06/28 03:32:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "nodes/memnodes.h"
 #include "utils/excid.h"
-#include "utils/module.h"
-
-
-
-#undef MemoryContextAlloc
-#undef MemoryContextFree
-#undef malloc
-#undef free
-
-/*
- * Global State
- */
-static int MemoryContextEnableCount = 0;
-
-#define MemoryContextEnabled   (MemoryContextEnableCount > 0)
+#include "utils/memutils.h"
 
-static OrderedSetData ActiveGlobalMemorySetData;       /* uninitialized */
-
-#define ActiveGlobalMemorySet  (&ActiveGlobalMemorySetData)
-
-/*
- * description of allocated memory representation goes here
- */
-
-#define PSIZE(PTR)     (*((int32 *)(PTR) - 1))
-#define PSIZEALL(PTR)  (*((int32 *)(PTR) - 1) + sizeof (int32))
-#define PSIZESKIP(PTR) ((char *)((int32 *)(PTR) + 1))
-#define PSIZEFIND(PTR) ((char *)((int32 *)(PTR) - 1))
-#define PSIZESPACE(LEN) ((LEN) + sizeof (int32))
-
-/*
- * AllocSizeIsValid
- *     True iff 0 < size and size <= MaxAllocSize.
- */
-#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
 
 /*****************************************************************************
  *   GLOBAL MEMORY                                                          *
@@ -59,478 +32,451 @@ static OrderedSetData ActiveGlobalMemorySetData;      /* uninitialized */
 
 /*
  * CurrentMemoryContext
- *     Memory context for general global allocations.
+ *     Default memory context for allocations.
  */
 DLLIMPORT MemoryContext CurrentMemoryContext = NULL;
 
-/*****************************************************************************
- *   PRIVATE DEFINITIONS                                                    *
- *****************************************************************************/
-
-static Pointer GlobalMemoryAlloc(GlobalMemory this, Size size);
-static void GlobalMemoryFree(GlobalMemory this, Pointer pointer);
-static Pointer GlobalMemoryRealloc(GlobalMemory this, Pointer pointer,
-                   Size size);
-static char *GlobalMemoryGetName(GlobalMemory this);
-static void GlobalMemoryDump(GlobalMemory this);
-
-#ifdef NOT_USED
-static void DumpGlobalMemories(void);
-
-#endif
-
 /*
- * Global Memory Methods
+ * Standard top-level contexts
  */
+MemoryContext TopMemoryContext = NULL;
+MemoryContext ErrorContext = NULL;
+MemoryContext PostmasterContext = NULL;
+MemoryContext CacheMemoryContext = NULL;
+MemoryContext QueryContext = NULL;
+MemoryContext TopTransactionContext = NULL;
+MemoryContext TransactionCommandContext = NULL;
 
-static struct MemoryContextMethodsData GlobalContextMethodsData = {
-   GlobalMemoryAlloc,          /* Pointer (*)(this, uint32)  palloc */
-   GlobalMemoryFree,           /* void (*)(this, Pointer)    pfree */
-   GlobalMemoryRealloc,        /* Pointer (*)(this, Pointer) repalloc */
-   GlobalMemoryGetName,        /* char* (*)(this)            getName */
-   GlobalMemoryDump            /* void (*)(this)             dump */
-};
 
-/*
- * Note:
- *     TopGlobalMemory is handled specially because of bootstrapping.
- */
-/* extern bool EqualGlobalMemory(); */
+/*****************************************************************************
+ *   EXPORTED ROUTINES                                                      *
+ *****************************************************************************/
 
-static struct GlobalMemoryData TopGlobalMemoryData = {
-   T_GlobalMemory,             /* NodeTag              tag       */
-   &GlobalContextMethodsData,  /* ContextMethods       method    */
-   {NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
-   /* free AllocSet   */
-   "TopGlobal",                /* char* name      */
-   {0}                         /* uninitialized OrderedElemData elemD */
-};
 
 /*
- * TopMemoryContext
- *     Memory context for general global allocations.
+ * MemoryContextInit
+ *     Start up the memory-context subsystem.
  *
- * Note:
- *     Don't use this memory context for random allocations.  If you
- *     allocate something here, you are expected to clean it up when
- *     appropriate.
- */
-MemoryContext TopMemoryContext = (MemoryContext) &TopGlobalMemoryData;
-
-
-
-
-/*
- * Module State
- */
-
-/*
- * EnableMemoryContext
- *     Enables/disables memory management and global contexts.
+ * This must be called before creating contexts or allocating memory in
+ * contexts.  TopMemoryContext and ErrorContext are initialized here;
+ * other contexts must be created afterwards.
  *
- * Note:
- *     This must be called before creating contexts or allocating memory.
- *     This must be called before other contexts are created.
+ * In normal multi-backend operation, this is called once during
+ * postmaster startup, and not at all by individual backend startup
+ * (since the backends inherit an already-initialized context subsystem
+ * by virtue of being forked off the postmaster).
  *
- * Exceptions:
- *     BadArg if on is invalid.
- *     BadState if on is false when disabled.
+ * In a standalone backend this must be called during backend startup.
  */
 void
-EnableMemoryContext(bool on)
+MemoryContextInit(void)
 {
-   static bool processing = false;
-
-   AssertState(!processing);
-   AssertArg(BoolIsValid(on));
-
-   if (BypassEnable(&MemoryContextEnableCount, on))
-       return;
-
-   processing = true;
-
-   if (on)
-   {                           /* initialize */
-       /* initialize TopGlobalMemoryData.setData */
-       AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
-                    (Size) 0);
-
-       /* make TopGlobalMemoryData member of ActiveGlobalMemorySet */
-       OrderedSetInit(ActiveGlobalMemorySet,
-                      offsetof(struct GlobalMemoryData, elemData));
-       OrderedElemPushInto(&TopGlobalMemoryData.elemData,
-                           ActiveGlobalMemorySet);
-
-       /* initialize CurrentMemoryContext */
-       CurrentMemoryContext = TopMemoryContext;
-
-   }
-   else
-   {                           /* cleanup */
-       GlobalMemory context;
-
-       /* walk the list of allocations */
-       while (PointerIsValid(context = (GlobalMemory)
-                             OrderedSetGetHead(ActiveGlobalMemorySet)))
-       {
-
-           if (context == &TopGlobalMemoryData)
-           {
-               /* don't free it and clean it last */
-               OrderedElemPop(&TopGlobalMemoryData.elemData);
-           }
-           else
-               GlobalMemoryDestroy(context);
-           /* what is needed for the top? */
-       }
-
-       /*
-        * Freeing memory here should be safe as this is called only after
-        * all modules which allocate in TopMemoryContext have been
-        * disabled.
-        */
-
-       /* step through remaining allocations and log */
-       /* AllocSetStep(...); */
-
-       /* deallocate whatever is left */
-       AllocSetReset(&TopGlobalMemoryData.setData);
-   }
-
-   processing = false;
+   AssertState(TopMemoryContext == NULL);
+   /*
+    * Initialize TopMemoryContext as an AllocSetContext with slow
+    * growth rate --- we don't really expect much to be allocated in it.
+    *
+    * (There is special-case code in MemoryContextCreate() for this call.)
+    */
+   TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
+                                            "TopMemoryContext",
+                                            8 * 1024,
+                                            8 * 1024,
+                                            8 * 1024);
+   /*
+    * Not having any other place to point CurrentMemoryContext,
+    * make it point to TopMemoryContext.  Caller should change this soon!
+    */
+   CurrentMemoryContext = TopMemoryContext;
+   /*
+    * Initialize ErrorContext as an AllocSetContext with slow
+    * growth rate --- we don't really expect much to be allocated in it.
+    * More to the point, require it to contain at least 8K at all times.
+    * This is the only case where retained memory in a context is
+    * *essential* --- we want to be sure ErrorContext still has some
+    * memory even if we've run out elsewhere!
+    */
+   ErrorContext = AllocSetContextCreate(TopMemoryContext,
+                                        "ErrorContext",
+                                        8 * 1024,
+                                        8 * 1024,
+                                        8 * 1024);
 }
 
 /*
- * MemoryContextAlloc
- *     Returns pointer to aligned allocated memory in the given context.
- *
- * Note:
- *     none
+ * MemoryContextReset
+ *     Release all space allocated within a context and its descendants,
+ *     but don't delete the contexts themselves.
  *
- * Exceptions:
- *     BadState if called before InitMemoryManager.
- *     BadArg if context is invalid or if size is 0.
- *     BadAllocSize if size is larger than MaxAllocSize.
+ * The type-specific reset routine handles the context itself, but we
+ * have to do the recursion for the children.
  */
-Pointer
-MemoryContextAlloc(MemoryContext context, Size size)
+void
+MemoryContextReset(MemoryContext context)
 {
-   AssertState(MemoryContextEnabled);
-   AssertArg(MemoryContextIsValid(context));
-
-   LogTrap(!AllocSizeIsValid(size), BadAllocSize,
-           ("size=%d [0x%x]", size, size));
-
-   return context->method->alloc(context, size);
+   MemoryContextResetChildren(context);
+   (*context->methods->reset) (context);
 }
 
 /*
- * MemoryContextFree
- *     Frees allocated memory referenced by pointer in the given context.
- *
- * Note:
- *     none
- *
- * Exceptions:
- *     ???
- *     BadArgumentsErr if firstTime is true for subsequent calls.
+ * MemoryContextResetChildren
+ *     Release all space allocated within a context's descendants,
+ *     but don't delete the contexts themselves.  The named context
+ *     itself is not touched.
  */
 void
-MemoryContextFree(MemoryContext context, Pointer pointer)
+MemoryContextResetChildren(MemoryContext context)
 {
-   AssertState(MemoryContextEnabled);
-   AssertArg(MemoryContextIsValid(context));
-   AssertArg(PointerIsValid(pointer));
+   MemoryContext   child;
 
-   context->method->free_p(context, pointer);
+   for (child = context->firstchild; child != NULL; child = child->nextchild)
+   {
+       MemoryContextReset(child);
+   }
 }
 
 /*
- * MemoryContextRelloc
- *     Returns pointer to aligned allocated memory in the given context.
+ * MemoryContextDelete
+ *     Delete a context and its descendants, and release all space
+ *     allocated therein.
  *
- * Note:
- *     none
- *
- * Exceptions:
- *     ???
- *     BadArgumentsErr if firstTime is true for subsequent calls.
+ * The type-specific delete routine removes all subsidiary storage
+ * for the context, but we have to delete the context node itself,
+ * as well as recurse to get the children.  We must also delink the
+ * node from its parent, if it has one.
  */
-Pointer
-MemoryContextRealloc(MemoryContext context,
-                    Pointer pointer,
-                    Size size)
+void
+MemoryContextDelete(MemoryContext context)
 {
-   AssertState(MemoryContextEnabled);
-   AssertArg(MemoryContextIsValid(context));
-   AssertArg(PointerIsValid(pointer));
+   /* We had better not be deleting TopMemoryContext ... */
+   Assert(context != TopMemoryContext);
+   /* And not CurrentMemoryContext, either */
+   Assert(context != CurrentMemoryContext);
+
+   MemoryContextDeleteChildren(context);
+   /*
+    * We delink the context from its parent before deleting it,
+    * so that if there's an error we won't have deleted/busted
+    * contexts still attached to the context tree.  Better a leak
+    * than a crash.
+    */
+   if (context->parent)
+   {
+       MemoryContext   parent = context->parent;
 
-   LogTrap(!AllocSizeIsValid(size), BadAllocSize,
-           ("size=%d [0x%x]", size, size));
+       if (context == parent->firstchild)
+       {
+           parent->firstchild = context->nextchild;
+       }
+       else
+       {
+           MemoryContext   child;
 
-   return context->method->realloc(context, pointer, size);
+           for (child = parent->firstchild; child; child = child->nextchild)
+           {
+               if (context == child->nextchild)
+               {
+                   child->nextchild = context->nextchild;
+                   break;
+               }
+           }
+       }
+   }
+   (*context->methods->delete) (context);
+   pfree(context);
 }
 
 /*
- * MemoryContextGetName
- *     Returns pointer to aligned allocated memory in the given context.
- *
- * Note:
- *     none
- *
- * Exceptions:
- *     ???
- *     BadArgumentsErr if firstTime is true for subsequent calls.
+ * MemoryContextDeleteChildren
+ *     Delete all the descendants of the named context and release all
+ *     space allocated therein.  The named context itself is not touched.
  */
-#ifdef NOT_USED
-char *
-MemoryContextGetName(MemoryContext context)
+void
+MemoryContextDeleteChildren(MemoryContext context)
 {
-   AssertState(MemoryContextEnabled);
-   AssertArg(MemoryContextIsValid(context));
-
-   return context->method->getName(context);
+   /*
+    * MemoryContextDelete will delink the child from me,
+    * so just iterate as long as there is a child.
+    */
+   while (context->firstchild != NULL)
+   {
+       MemoryContextDelete(context->firstchild);
+   }
 }
 
-#endif
-
 /*
- * PointerGetAllocSize
- *     Returns size of aligned allocated memory given pointer to it.
+ * MemoryContextResetAndDeleteChildren
+ *     Release all space allocated within a context and delete all
+ *     its descendants.
  *
- * Note:
- *     none
- *
- * Exceptions:
- *     ???
- *     BadArgumentsErr if firstTime is true for subsequent calls.
+ * This is a common combination case where we want to preserve the
+ * specific context but get rid of absolutely everything under it.
  */
-#ifdef NOT_USED
-Size
-PointerGetAllocSize(Pointer pointer)
+void
+MemoryContextResetAndDeleteChildren(MemoryContext context)
 {
-   AssertState(MemoryContextEnabled);
-   AssertArg(PointerIsValid(pointer));
-
-   return PSIZE(pointer);
+   MemoryContextDeleteChildren(context);
+   (*context->methods->reset) (context);
 }
 
-#endif
-
 /*
- * MemoryContextSwitchTo
- *     Returns the current context; installs the given context.
+ * MemoryContextStats
+ *     Print statistics about the named context and all its descendants.
  *
- * Note:
- *     none
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadArg if context is invalid.
+ * This is just a debugging utility, so it's not fancy.  The statistics
+ * are merely sent to stderr.
  */
-MemoryContext
-MemoryContextSwitchTo(MemoryContext context)
+void
+MemoryContextStats(MemoryContext context)
 {
-   MemoryContext old;
+   MemoryContext   child;
 
-   AssertState(MemoryContextEnabled);
-   AssertArg(MemoryContextIsValid(context));
-
-   old = CurrentMemoryContext;
-   CurrentMemoryContext = context;
-   return old;
+   (*context->methods->stats) (context);
+   for (child = context->firstchild; child != NULL; child = child->nextchild)
+   {
+       MemoryContextStats(child);
+   }
 }
 
 /*
- * External Functions
- */
-/*
- * CreateGlobalMemory
- *     Returns new global memory context.
- *
- * Note:
- *     Assumes name is static.
+ * MemoryContextContains
+ *     Detect whether an allocated chunk of memory belongs to a given
+ *     context or not.
  *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadState if called outside TopMemoryContext (TopGlobalMemory).
- *     BadArg if name is invalid.
+ * Caution: this test is reliable as long as 'pointer' does point to
+ * a chunk of memory allocated from *some* context.  If 'pointer' points
+ * at memory obtained in some other way, there is a small chance of a
+ * false-positive result, since the bits right before it might look like
+ * a valid chunk header by chance.
  */
-GlobalMemory
-CreateGlobalMemory(char *name) /* XXX MemoryContextName */
+bool
+MemoryContextContains(MemoryContext context, void *pointer)
 {
-   GlobalMemory context;
-   MemoryContext savecxt;
-
-   AssertState(MemoryContextEnabled);
-
-   savecxt = MemoryContextSwitchTo(TopMemoryContext);
-
-   context = (GlobalMemory) newNode(sizeof(struct GlobalMemoryData), T_GlobalMemory);
-   context->method = &GlobalContextMethodsData;
-   context->name = name;       /* assumes name is static */
-   AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0);
-
-   /* link the context */
-   OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet);
-
-   MemoryContextSwitchTo(savecxt);
-   return context;
+   StandardChunkHeader    *header;
+
+   /*
+    * Try to detect bogus pointers handed to us, poorly though we can.
+    * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+    * an allocated chunk.
+    */
+   if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
+       return false;
+   /*
+    * OK, it's probably safe to look at the chunk header.
+    */
+   header = (StandardChunkHeader *)
+       ((char *) pointer - STANDARDCHUNKHEADERSIZE);
+   /*
+    * If the context link doesn't match then we certainly have a
+    * non-member chunk.  Also check for a reasonable-looking size
+    * as extra guard against being fooled by bogus pointers.
+    */
+   if (header->context == context && AllocSizeIsValid(header->size))
+       return true;
+   return false;
 }
 
-/*
- * GlobalMemoryDestroy
- *     Destroys given global memory context.
+/*--------------------
+ * MemoryContextCreate
+ *     Context-type-independent part of context creation.
+ *
+ * This is only intended to be called by context-type-specific
+ * context creation routines, not by the unwashed masses.
+ *
+ * The context creation procedure is a little bit tricky because
+ * we want to be sure that we don't leave the context tree invalid
+ * in case of failure (such as insufficient memory to allocate the
+ * context node itself).  The procedure goes like this:
+ * 1.  Context-type-specific routine first calls MemoryContextCreate(),
+ *     passing the appropriate tag/size/methods values (the methods
+ *     pointer will ordinarily point to statically allocated data).
+ *     The parent and name parameters usually come from the caller.
+ * 2.  MemoryContextCreate() attempts to allocate the context node,
+ *     plus space for the name.  If this fails we can elog() with no
+ *     damage done.
+ * 3.  We fill in all of the type-independent MemoryContext fields.
+ * 4.  We call the type-specific init routine (using the methods pointer).
+ *     The init routine is required to make the node minimally valid
+ *     with zero chance of failure --- it can't allocate more memory,
+ *     for example.
+ * 5.  Now we have a minimally valid node that can behave correctly
+ *     when told to reset or delete itself.  We link the node to its
+ *     parent (if any), making the node part of the context tree.
+ * 6.  We return to the context-type-specific routine, which finishes
+ *     up type-specific initialization.  This routine can now do things
+ *     that might fail (like allocate more memory), so long as it's
+ *     sure the node is left in a state that delete will handle.
+ *
+ * This protocol doesn't prevent us from leaking memory if step 6 fails
+ * during creation of a top-level context, since there's no parent link
+ * in that case.  However, if you run out of memory while you're building
+ * a top-level context, you might as well go home anyway...
  *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadState if called outside TopMemoryContext (TopGlobalMemory).
- *     BadArg if context is invalid GlobalMemory.
- *     BadArg if context is TopMemoryContext (TopGlobalMemory).
+ * Normally, the context node and the name are allocated from
+ * TopMemoryContext (NOT from the parent context, since the node must
+ * survive resets of its parent context!).  However, this routine is itself
+ * used to create TopMemoryContext!  If we see that TopMemoryContext is NULL,
+ * we assume we are creating TopMemoryContext and use malloc() to allocate
+ * the node.
+ *
+ * Note that the name field of a MemoryContext does not point to
+ * separately-allocated storage, so it should not be freed at context
+ * deletion.
+ *--------------------
  */
-void
-GlobalMemoryDestroy(GlobalMemory context)
+MemoryContext
+MemoryContextCreate(NodeTag tag, Size size,
+                   MemoryContextMethods *methods,
+                   MemoryContext parent,
+                   const char *name)
 {
-   AssertState(MemoryContextEnabled);
-   AssertArg(IsA(context, GlobalMemory));
-   AssertArg(context != &TopGlobalMemoryData);
+   MemoryContext   node;
+   Size            needed = size + strlen(name) + 1;
 
-   AllocSetReset(&context->setData);
-
-   /* unlink and delete the context */
-   OrderedElemPop(&context->elemData);
-   MemoryContextFree(TopMemoryContext, (Pointer) context);
-}
+   /* Get space for node and name */
+   if (TopMemoryContext != NULL)
+   {
+       /* Normal case: allocate the node in TopMemoryContext */
+       node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
+                                                 needed);
+   }
+   else
+   {
+       /* Special case for startup: use good ol' malloc */
+       node = (MemoryContext) malloc(needed);
+       Assert(node != NULL);
+   }
 
-/*****************************************************************************
- *   PRIVATE                                                                *
- *****************************************************************************/
+   /* Initialize the node as best we can */
+   MemSet(node, 0, size);
+   node->type = tag;
+   node->methods = methods;
+   node->parent = NULL;        /* for the moment */
+   node->firstchild = NULL;
+   node->nextchild = NULL;
+   node->name = ((char *) node) + size;
+   strcpy(node->name, name);
+
+   /* Type-specific routine finishes any other essential initialization */
+   (*node->methods->init) (node);
+
+   /* OK to link node to parent (if any) */
+   if (parent)
+   {
+       node->parent = parent;
+       node->nextchild = parent->firstchild;
+       parent->firstchild = node;
+   }
 
-/*
- * GlobalMemoryAlloc
- *     Returns pointer to aligned space in the global context.
- *
- * Exceptions:
- *     ExhaustedMemory if allocation fails.
- */
-static Pointer
-GlobalMemoryAlloc(GlobalMemory this, Size size)
-{
-   return AllocSetAlloc(&this->setData, size);
+   /* Return to type-specific creation routine to finish up */
+   return node;
 }
 
 /*
- * GlobalMemoryFree
- *     Frees allocated memory in the global context.
+ * MemoryContextAlloc
+ *     Allocate space within the specified context.
  *
- * Exceptions:
- *     BadContextErr if current context is not the global context.
- *     BadArgumentsErr if pointer is invalid.
+ * This could be turned into a macro, but we'd have to import
+ * nodes/memnodes.h into postgres.h which seems a bad idea.
  */
-static void
-GlobalMemoryFree(GlobalMemory this,
-                Pointer pointer)
+void *
+MemoryContextAlloc(MemoryContext context, Size size)
 {
-   AllocSetFree(&this->setData, pointer);
-}
+   AssertArg(MemoryContextIsValid(context));
 
-/*
- * GlobalMemoryRealloc
- *     Returns pointer to aligned space in the global context.
- *
- * Note:
- *     Memory associated with the pointer is freed before return.
- *
- * Exceptions:
- *     BadContextErr if current context is not the global context.
- *     BadArgumentsErr if pointer is invalid.
- *     NoMoreMemoryErr if allocation fails.
- */
-static Pointer
-GlobalMemoryRealloc(GlobalMemory this,
-                   Pointer pointer,
-                   Size size)
-{
-   return AllocSetRealloc(&this->setData, pointer, size);
+   LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+           ("size=%d [0x%x]", size, size));
+
+   return (*context->methods->alloc) (context, size);
 }
 
 /*
- * GlobalMemoryGetName
- *     Returns name string for context.
- *
- * Exceptions:
- *     ???
+ * pfree
+ *     Release an allocated chunk.
  */
-static char *
-GlobalMemoryGetName(GlobalMemory this)
+void
+pfree(void *pointer)
 {
-   return this->name;
+   StandardChunkHeader    *header;
+
+   /*
+    * Try to detect bogus pointers handed to us, poorly though we can.
+    * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+    * an allocated chunk.
+    */
+   Assert(pointer != NULL);
+   Assert(pointer == (void *) MAXALIGN(pointer));
+   /*
+    * OK, it's probably safe to look at the chunk header.
+    */
+   header = (StandardChunkHeader *)
+       ((char *) pointer - STANDARDCHUNKHEADERSIZE);
+
+   AssertArg(MemoryContextIsValid(header->context));
+
+    (*header->context->methods->free_p) (header->context, pointer);
 }
 
 /*
- * GlobalMemoryDump
- *     Dumps global memory context for debugging.
+ * repalloc
  *
- * Exceptions:
- *     ???
  */
-static void
-GlobalMemoryDump(GlobalMemory this)
+void *
+repalloc(void *pointer, Size size)
 {
-   GlobalMemory context;
-
-   printf("--\n%s:\n", GlobalMemoryGetName(this));
+   StandardChunkHeader    *header;
+
+   /*
+    * Try to detect bogus pointers handed to us, poorly though we can.
+    * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+    * an allocated chunk.
+    */
+   Assert(pointer != NULL);
+   Assert(pointer == (void *) MAXALIGN(pointer));
+   /*
+    * OK, it's probably safe to look at the chunk header.
+    */
+   header = (StandardChunkHeader *)
+       ((char *) pointer - STANDARDCHUNKHEADERSIZE);
+
+   AssertArg(MemoryContextIsValid(header->context));
 
-   context = (GlobalMemory) OrderedElemGetPredecessor(&this->elemData);
-   if (PointerIsValid(context))
-       printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
-
-   context = (GlobalMemory) OrderedElemGetSuccessor(&this->elemData);
-   if (PointerIsValid(context))
-       printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
+   LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+           ("size=%d [0x%x]", size, size));
 
-   AllocSetDump(&this->setData);
+    return (*header->context->methods->realloc) (header->context,
+                                                pointer, size);
 }
 
 /*
- * DumpGlobalMemories
- *     Dumps all global memory contexts for debugging.
- *
- * Exceptions:
- *     ???
+ * MemoryContextSwitchTo
+ *     Returns the current context; installs the given context.
  */
-#ifdef NOT_USED
-static void
-DumpGlobalMemories()
+MemoryContext
+MemoryContextSwitchTo(MemoryContext context)
 {
-   GlobalMemory context;
-
-   context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
+   MemoryContext old;
 
-   while (PointerIsValid(context))
-   {
-       GlobalMemoryDump(context);
+   AssertArg(MemoryContextIsValid(context));
 
-       context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
-   }
+   old = CurrentMemoryContext;
+   CurrentMemoryContext = context;
+   return old;
 }
 
-#endif
-
 /*
- * GlobalMemoryStats
- *     Displays stats about memory consumption of all global contexts.
+ * MemoryContextStrdup
+ *     Like strdup(), but allocate from the specified context
  */
-void
-GlobalMemoryStats(void)
+char *
+MemoryContextStrdup(MemoryContext context, const char *string)
 {
-   GlobalMemory context;
+   char       *nstr;
+   Size        len = strlen(string) + 1;
 
-   context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
+   nstr = (char *) MemoryContextAlloc(context, len);
 
-   while (PointerIsValid(context))
-   {
-       AllocSetStats(&context->setData, GlobalMemoryGetName(context));
-       context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
-   }
+   memcpy(nstr, string, len);
+
+   return nstr;
 }
diff --git a/src/backend/utils/mmgr/oset.c b/src/backend/utils/mmgr/oset.c
deleted file mode 100644 (file)
index 86487ab..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * oset.c
- *   Fixed format ordered set definitions.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/oset.c,v 1.17 2000/04/12 17:16:10 momjian Exp $
- *
- * NOTE
- *   XXX This is a preliminary implementation which lacks fail-fast
- *   XXX validity checking of arguments.
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "utils/memutils.h"
-
-static Pointer OrderedElemGetBase(OrderedElem elem);
-static void OrderedElemPush(OrderedElem elem);
-static void OrderedElemPushHead(OrderedElem elem);
-
-/*
- * OrderedElemGetBase
- *     Returns base of enclosing structure.
- */
-static Pointer
-OrderedElemGetBase(OrderedElem elem)
-{
-   if (elem == (OrderedElem) NULL)
-       return (Pointer) NULL;
-
-   return (Pointer) ((char *) (elem) - (elem)->set->offset);
-}
-
-/*
- * OrderedSetInit
- */
-void
-OrderedSetInit(OrderedSet set, Offset offset)
-{
-   set->head = (OrderedElem) &set->dummy;
-   set->dummy = NULL;
-   set->tail = (OrderedElem) &set->head;
-   set->offset = offset;
-}
-
-/*
- * OrderedSetContains
- *     True iff ordered set contains given element.
- */
-#ifdef NOT_USED
-bool
-OrderedSetContains(OrderedSet set, OrderedElem elem)
-{
-   return (bool) (elem->set == set && (elem->next || elem->prev));
-}
-
-#endif
-
-/*
- * OrderedSetGetHead
- */
-Pointer
-OrderedSetGetHead(OrderedSet set)
-{
-   OrderedElem elem;
-
-   elem = set->head;
-   if (elem->next)
-       return OrderedElemGetBase(elem);
-   return NULL;
-}
-
-/*
- * OrderedSetGetTail
- */
-#ifdef NOT_USED
-Pointer
-OrderedSetGetTail(OrderedSet set)
-{
-   OrderedElem elem;
-
-   elem = set->tail;
-   if (elem->prev)
-       return OrderedElemGetBase(elem);
-   return NULL;
-}
-
-#endif
-
-/*
- * OrderedElemGetPredecessor
- */
-Pointer
-OrderedElemGetPredecessor(OrderedElem elem)
-{
-   elem = elem->prev;
-   if (elem->prev)
-       return OrderedElemGetBase(elem);
-   return NULL;
-}
-
-/*
- * OrderedElemGetSuccessor
- */
-Pointer
-OrderedElemGetSuccessor(OrderedElem elem)
-{
-   elem = elem->next;
-   if (elem->next)
-       return OrderedElemGetBase(elem);
-   return NULL;
-}
-
-/*
- * OrderedElemPop
- */
-void
-OrderedElemPop(OrderedElem elem)
-{
-   elem->next->prev = elem->prev;
-   elem->prev->next = elem->next;
-   /* assignments used only for error detection */
-   elem->next = NULL;
-   elem->prev = NULL;
-}
-
-/*
- * OrderedElemPushInto
- */
-void
-OrderedElemPushInto(OrderedElem elem, OrderedSet set)
-{
-   elem->set = set;
-   /* mark as unattached */
-   elem->next = NULL;
-   elem->prev = NULL;
-   OrderedElemPush(elem);
-}
-
-/*
- * OrderedElemPush
- */
-static void
-OrderedElemPush(OrderedElem elem)
-{
-   OrderedElemPushHead(elem);
-}
-
-/*
- * OrderedElemPushHead
- */
-static void
-OrderedElemPushHead(OrderedElem elem)
-{
-   elem->next = elem->set->head;
-   elem->prev = (OrderedElem) &elem->set->head;
-   elem->next->prev = elem;
-   elem->prev->next = elem;
-}
diff --git a/src/backend/utils/mmgr/palloc.c b/src/backend/utils/mmgr/palloc.c
deleted file mode 100644 (file)
index e714225..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * palloc.c
- *   POSTGRES memory allocator code.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.18 2000/05/30 00:49:57 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-
-#include "postgres.h"
-
-
-
-/* ----------------------------------------------------------------
- *     User library functions
- * ----------------------------------------------------------------
- */
-
-/* ----------
- * palloc(), pfree() and repalloc() are now macros in palloc.h
- * ----------
- */
-
-char *
-pstrdup(const char *string)
-{
-   char       *nstr;
-   int         len;
-
-   nstr = palloc(len = strlen(string) + 1);
-   memcpy(nstr, string, len);
-
-   return nstr;
-}
index 71e94b7096d3f612630601f2453602004b6c950b..21aeb0a8a5f9080a841177efbbfaf1f68fbfc616 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.36 2000/04/12 17:16:10 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.37 2000/06/28 03:32:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *
  * struct PortalD {
  *     char*                           name;
- *     classObj(PortalVariableMemory)  variable;
- *     classObj(PortalHeapMemory)      heap;
+ *     classObj(MemoryContext)         heap;
  *     List                            queryDesc;
  *     EState                          state;
  *     void                            (*cleanup) ARGS((Portal portal));
  * };
  *
  *     I hope this makes things clearer to whoever reads this -cim 2/22/91
- *
- *     Here is an old comment taken from nodes/memnodes.h
- *
- * MemoryContext
- *     A logical context in which memory allocations occur.
- *
- * The types of memory contexts can be thought of as members of the
- * following inheritance hierarchy with properties summarized below.
- *
- *                     Node
- *                     |
- *             MemoryContext___
- *             /               \
- *     GlobalMemory    PortalMemoryContext
- *                     /               \
- *     PortalVariableMemory    PortalHeapMemory
- *
- *                     Flushed at      Flushed at      Checkpoints
- *                     Transaction     Portal
- *                     Commit          Close
- *
- * GlobalMemory                    n               n               n
- * PortalVariableMemory            n               y               n
- * PortalHeapMemory                y               y               y *
- *
  */
 
 #include "postgres.h"
 
 #include "lib/hasht.h"
-#include "utils/module.h"
+#include "utils/memutils.h"
 #include "utils/portal.h"
 
 static void CollectNamedPortals(Portal *portalP, int destroy);
-static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
-static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
-static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
-
-/* ----------------
- *     ALLOCFREE_ERROR_ABORT
- *     define this if you want a core dump when you try to
- *     free memory already freed -cim 2/9/91
- * ----------------
- */
-#undef ALLOCFREE_ERROR_ABORT
 
 /* ----------------
  *     Global state
  * ----------------
  */
 
-static int PortalManagerEnableCount = 0;
-
 #define MAX_PORTALNAME_LEN     64      /* XXX LONGALIGNable value */
 
 typedef struct portalhashent
@@ -109,8 +70,6 @@ typedef struct portalhashent
    Portal      portal;
 } PortalHashEnt;
 
-#define PortalManagerEnabled   (PortalManagerEnableCount >= 1)
-
 static HTAB *PortalHashTable = NULL;
 
 #define PortalHashTableLookup(NAME, PORTAL) \
@@ -158,263 +117,13 @@ do { \
        elog(NOTICE, "trying to delete portal name that does not exist."); \
 } while(0)
 
-static GlobalMemory PortalMemory = NULL;
-static char PortalMemoryName[] = "Portal";
-
-static Portal BlankPortal = NULL;
-
-/* ----------------
- *     Internal class definitions
- * ----------------
- */
-typedef struct HeapMemoryBlockData
-{
-   AllocSetData setData;
-   FixedItemData itemData;
-} HeapMemoryBlockData;
-
-typedef HeapMemoryBlockData *HeapMemoryBlock;
-
-#define HEAPMEMBLOCK(context) \
-   ((HeapMemoryBlock)(context)->block)
-
-/* ----------------------------------------------------------------
- *               Variable and heap memory methods
- * ----------------------------------------------------------------
- */
-/* ----------------
- *     PortalVariableMemoryAlloc
- * ----------------
- */
-static Pointer
-PortalVariableMemoryAlloc(PortalVariableMemory this,
-                         Size size)
-{
-   return AllocSetAlloc(&this->setData, size);
-}
-
-/* ----------------
- *     PortalVariableMemoryFree
- * ----------------
- */
-static void
-PortalVariableMemoryFree(PortalVariableMemory this,
-                        Pointer pointer)
-{
-   AllocSetFree(&this->setData, pointer);
-}
-
-/* ----------------
- *     PortalVariableMemoryRealloc
- * ----------------
- */
-static Pointer
-PortalVariableMemoryRealloc(PortalVariableMemory this,
-                           Pointer pointer,
-                           Size size)
-{
-   return AllocSetRealloc(&this->setData, pointer, size);
-}
-
-/* ----------------
- *     PortalVariableMemoryGetName
- * ----------------
- */
-static char *
-PortalVariableMemoryGetName(PortalVariableMemory this)
-{
-   return vararg_format("%s-var", PortalVariableMemoryGetPortal(this)->name);
-}
-
-/* ----------------
- *     PortalVariableMemoryDump
- * ----------------
- */
-static void
-PortalVariableMemoryDump(PortalVariableMemory this)
-{
-   printf("--\n%s:\n", PortalVariableMemoryGetName(this));
-
-   AllocSetDump(&this->setData);       /* XXX is this the right interface */
-}
-
-/* ----------------
- *     PortalHeapMemoryAlloc
- * ----------------
- */
-static Pointer
-PortalHeapMemoryAlloc(PortalHeapMemory this,
-                     Size size)
-{
-   HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
-   AssertState(PointerIsValid(block));
-
-   return AllocSetAlloc(&block->setData, size);
-}
-
-/* ----------------
- *     PortalHeapMemoryFree
- * ----------------
- */
-static void
-PortalHeapMemoryFree(PortalHeapMemory this,
-                    Pointer pointer)
-{
-   HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
-   AssertState(PointerIsValid(block));
-
-   if (AllocSetContains(&block->setData, pointer))
-       AllocSetFree(&block->setData, pointer);
-   else
-   {
-       elog(NOTICE,
-            "PortalHeapMemoryFree: 0x%p not in alloc set!",
-            pointer);
-#ifdef ALLOCFREE_ERROR_ABORT
-       Assert(AllocSetContains(&block->setData, pointer));
-#endif  /* ALLOCFREE_ERROR_ABORT */
-   }
-}
-
-/* ----------------
- *     PortalHeapMemoryRealloc
- * ----------------
- */
-static Pointer
-PortalHeapMemoryRealloc(PortalHeapMemory this,
-                       Pointer pointer,
-                       Size size)
-{
-   HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
-   AssertState(PointerIsValid(block));
-
-   return AllocSetRealloc(&block->setData, pointer, size);
-}
-
-/* ----------------
- *     PortalHeapMemoryGetName
- * ----------------
- */
-static char *
-PortalHeapMemoryGetName(PortalHeapMemory this)
-{
-   return vararg_format("%s-heap", PortalHeapMemoryGetPortal(this)->name);
-}
-
-/* ----------------
- *     PortalHeapMemoryDump
- * ----------------
- */
-static void
-PortalHeapMemoryDump(PortalHeapMemory this)
-{
-   HeapMemoryBlock block;
-
-   printf("--\n%s:\n", PortalHeapMemoryGetName(this));
-
-   /* XXX is this the right interface */
-   if (PointerIsValid(this->block))
-       AllocSetDump(&HEAPMEMBLOCK(this)->setData);
-
-   /* dump the stack too */
-   for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
-        PointerIsValid(block);
-        block = (HeapMemoryBlock)
-        FixedStackGetNext(&this->stackData, (Pointer) block))
-   {
-
-       printf("--\n");
-       AllocSetDump(&block->setData);
-   }
-}
-
-/* ----------------------------------------------------------------
- *             variable / heap context method tables
- * ----------------------------------------------------------------
- */
-static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
-   PortalVariableMemoryAlloc,  /* Pointer (*)(this, uint32)    palloc */
-   PortalVariableMemoryFree,   /* void (*)(this, Pointer)      pfree */
-   PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer)   repalloc */
-   PortalVariableMemoryGetName,/* char* (*)(this)              getName */
-   PortalVariableMemoryDump    /* void (*)(this)               dump */
-};
-
-static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
-   PortalHeapMemoryAlloc,      /* Pointer (*)(this, uint32)    palloc */
-   PortalHeapMemoryFree,       /* void (*)(this, Pointer)      pfree */
-   PortalHeapMemoryRealloc,    /* Pointer (*)(this, Pointer)   repalloc */
-   PortalHeapMemoryGetName,    /* char* (*)(this)              getName */
-   PortalHeapMemoryDump        /* void (*)(this)               dump */
-};
+static MemoryContext PortalMemory = NULL;
 
 
 /* ----------------------------------------------------------------
  *               private internal support routines
  * ----------------------------------------------------------------
  */
-/* ----------------
- *     CreateNewBlankPortal
- * ----------------
- */
-static void
-CreateNewBlankPortal()
-{
-   Portal      portal;
-
-   AssertState(!PortalIsValid(BlankPortal));
-
-   /*
-    * make new portal structure
-    */
-   portal = (Portal)
-       MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
-
-   /*
-    * initialize portal variable context
-    */
-   NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
-   AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
-   portal->variable.method = &PortalVariableContextMethodsData;
-
-   /*
-    * initialize portal heap context
-    */
-   NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
-   portal->heap.block = NULL;
-   FixedStackInit(&portal->heap.stackData,
-                  offsetof(HeapMemoryBlockData, itemData));
-   portal->heap.method = &PortalHeapContextMethodsData;
-
-   /*
-    * set bogus portal name
-    */
-   portal->name = "** Blank Portal **";
-
-   /* initialize portal query */
-   portal->queryDesc = NULL;
-   portal->attinfo = NULL;
-   portal->state = NULL;
-   portal->cleanup = NULL;
-
-   /*
-    * install blank portal
-    */
-   BlankPortal = portal;
-}
-
-bool
-PortalNameIsSpecial(char *pname)
-{
-   if (strcmp(pname, VACPNAME) == 0)
-       return true;
-   if (strcmp(pname, TRUNCPNAME) == 0)
-       return true;
-   return false;
-}
 
 /*
  * This routine is used to collect all portals created in this xaction
@@ -447,12 +156,6 @@ CollectNamedPortals(Portal *portalP, int destroy)
        Assert(portalP);
        Assert(*portalP);
 
-       /*
-        * Don't delete special portals, up to portal creator to do this
-        */
-       if (PortalNameIsSpecial((*portalP)->name))
-           return;
-
        portalList[listIndex] = *portalP;
        listIndex++;
        if (listIndex == maxIndex)
@@ -472,179 +175,50 @@ AtEOXact_portals()
    CollectNamedPortals(NULL, 1);
 }
 
-/* ----------------
- *     PortalDump
- * ----------------
- */
-#ifdef NOT_USED
-static void
-PortalDump(Portal *thisP, int dummy)
-{
-   /* XXX state/argument checking here */
-
-   PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
-   PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
-}
-
-#endif
-
-/* ----------------
- *     DumpPortals
- * ----------------
- */
-#ifdef NOT_USED
-static void
-DumpPortals()
-{
-   /* XXX state checking here */
-
-   HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0);
-}
-
-#endif
-
 /* ----------------------------------------------------------------
  *                public portal interface functions
  * ----------------------------------------------------------------
  */
 /*
  * EnablePortalManager
- *     Enables/disables the portal management module.
+ *     Enables the portal management module at backend startup.
  */
 void
-EnablePortalManager(bool on)
+EnablePortalManager(void)
 {
-   static bool processing = false;
    HASHCTL     ctl;
 
-   AssertState(!processing);
-   AssertArg(BoolIsValid(on));
-
-   if (BypassEnable(&PortalManagerEnableCount, on))
-       return;
-
-   processing = true;
-
-   if (on)
-   {                           /* initialize */
-       EnableMemoryContext(true);
-
-       PortalMemory = CreateGlobalMemory(PortalMemoryName);
-
-       ctl.keysize = MAX_PORTALNAME_LEN;
-       ctl.datasize = sizeof(Portal);
-
-       /*
-        * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
-        * how many hash table entries to create, initially
-        */
-       PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
-
-       CreateNewBlankPortal();
-
-   }
-   else
-   {                           /* cleanup */
-       if (PortalIsValid(BlankPortal))
-       {
-           PortalDrop(&BlankPortal);
-           MemoryContextFree((MemoryContext) PortalMemory,
-                             (Pointer) BlankPortal);
-           BlankPortal = NULL;
-       }
-
-       /*
-        * Each portal must free its non-memory resources specially.
-        */
-       HashTableWalk(PortalHashTable, (HashtFunc) PortalDrop, 0);
-       hash_destroy(PortalHashTable);
-       PortalHashTable = NULL;
+   Assert(PortalMemory == NULL);
 
-       GlobalMemoryDestroy(PortalMemory);
-       PortalMemory = NULL;
+   PortalMemory = AllocSetContextCreate(TopMemoryContext,
+                                        "PortalMemory",
+                                        ALLOCSET_DEFAULT_MINSIZE,
+                                        ALLOCSET_DEFAULT_INITSIZE,
+                                        ALLOCSET_DEFAULT_MAXSIZE);
 
-       EnableMemoryContext(true);
-   }
+   ctl.keysize = MAX_PORTALNAME_LEN;
+   ctl.datasize = sizeof(Portal);
 
-   processing = false;
+   /*
+    * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
+    * how many hash table entries to create, initially
+    */
+   PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
 }
 
 /*
  * GetPortalByName
- *     Returns a portal given a portal name; returns blank portal given
- * NULL; returns invalid portal if portal not found.
- *
- * Exceptions:
- *     BadState if called when disabled.
+ *     Returns a portal given a portal name, or NULL if name not found.
  */
 Portal
 GetPortalByName(char *name)
 {
    Portal      portal;
 
-   AssertState(PortalManagerEnabled);
-
    if (PointerIsValid(name))
        PortalHashTableLookup(name, portal);
    else
-   {
-       if (!PortalIsValid(BlankPortal))
-           CreateNewBlankPortal();
-       portal = BlankPortal;
-   }
-
-   return portal;
-}
-
-/*
- * BlankPortalAssignName
- *     Returns former blank portal as portal with given name.
- *
- * Side effect:
- *     All references to the former blank portal become incorrect.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadState if called without an intervening call to GetPortalByName(NULL).
- *     BadArg if portal name is invalid.
- *     "WARN" if portal name is in use.
- */
-Portal
-BlankPortalAssignName(char *name)      /* XXX PortalName */
-{
-   Portal      portal;
-   uint16      length;
-
-   AssertState(PortalManagerEnabled);
-   AssertState(PortalIsValid(BlankPortal));
-   AssertArg(PointerIsValid(name));    /* XXX PortalName */
-
-   portal = GetPortalByName(name);
-   if (PortalIsValid(portal))
-   {
-       elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
-       return portal;
-   }
-
-   /*
-    * remove blank portal
-    */
-   portal = BlankPortal;
-   BlankPortal = NULL;
-
-   /*
-    * initialize portal name
-    */
-   length = 1 + strlen(name);
-   portal->name = (char *)
-       MemoryContextAlloc((MemoryContext) &portal->variable, length);
-
-   strncpy(portal->name, name, length);
-
-   /*
-    * put portal in table
-    */
-   PortalHashTableInsert(portal);
+       portal = NULL;
 
    return portal;
 }
@@ -666,7 +240,6 @@ PortalSetQuery(Portal portal,
               EState *state,
               void (*cleanup) (Portal portal))
 {
-   AssertState(PortalManagerEnabled);
    AssertArg(PortalIsValid(portal));
    AssertArg(IsA((Node *) state, EState));
 
@@ -687,7 +260,6 @@ PortalSetQuery(Portal portal,
 QueryDesc  *
 PortalGetQueryDesc(Portal portal)
 {
-   AssertState(PortalManagerEnabled);
    AssertArg(PortalIsValid(portal));
 
    return portal->queryDesc;
@@ -704,7 +276,6 @@ PortalGetQueryDesc(Portal portal)
 EState *
 PortalGetState(Portal portal)
 {
-   AssertState(PortalManagerEnabled);
    AssertArg(PortalIsValid(portal));
 
    return portal->state;
@@ -714,63 +285,48 @@ PortalGetState(Portal portal)
  * CreatePortal
  *     Returns a new portal given a name.
  *
- * Note:
- *     This is expected to be of very limited usability.  See instead,
- * BlankPortalAssignName.
- *
  * Exceptions:
  *     BadState if called when disabled.
  *     BadArg if portal name is invalid.
- *     "WARN" if portal name is in use.
+ *     "NOTICE" if portal name is in use (existing portal is returned!)
  */
 Portal
-CreatePortal(char *name)       /* XXX PortalName */
+CreatePortal(char *name)
 {
    Portal      portal;
-   uint16      length;
 
-   AssertState(PortalManagerEnabled);
-   AssertArg(PointerIsValid(name));    /* XXX PortalName */
+   AssertArg(PointerIsValid(name));
 
    portal = GetPortalByName(name);
    if (PortalIsValid(portal))
    {
-       elog(NOTICE, "CreatePortal: portal %s already exists", name);
+       elog(NOTICE, "CreatePortal: portal \"%s\" already exists", name);
        return portal;
    }
 
    /* make new portal structure */
-   portal = (Portal)
-       MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
+   portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
 
-   /* initialize portal variable context */
-   NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
-   AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
-   portal->variable.method = &PortalVariableContextMethodsData;
+   /* initialize portal name */
+   portal->name = MemoryContextStrdup(PortalMemory, name);
 
    /* initialize portal heap context */
-   NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
-   portal->heap.block = NULL;
-   FixedStackInit(&portal->heap.stackData,
-                  offsetof(HeapMemoryBlockData, itemData));
-   portal->heap.method = &PortalHeapContextMethodsData;
-
-   /* initialize portal name */
-   length = 1 + strlen(name);
-   portal->name = (char *)
-       MemoryContextAlloc((MemoryContext) &portal->variable, length);
-   strncpy(portal->name, name, length);
+   portal->heap = AllocSetContextCreate(PortalMemory,
+                                        "PortalHeapMemory",
+                                        ALLOCSET_DEFAULT_MINSIZE,
+                                        ALLOCSET_DEFAULT_INITSIZE,
+                                        ALLOCSET_DEFAULT_MAXSIZE);
 
    /* initialize portal query */
    portal->queryDesc = NULL;
    portal->attinfo = NULL;
    portal->state = NULL;
+
    portal->cleanup = NULL;
 
    /* put portal in table */
    PortalHashTableInsert(portal);
 
-   /* Trap(PointerIsValid(name), Unimplemented); */
    return portal;
 }
 
@@ -787,240 +343,29 @@ PortalDrop(Portal *portalP)
 {
    Portal      portal = *portalP;
 
-   AssertState(PortalManagerEnabled);
    AssertArg(PortalIsValid(portal));
 
-   /* remove portal from table if not blank portal */
-   if (portal != BlankPortal)
-       PortalHashTableDelete(portal);
+   /* remove portal from hash table */
+   PortalHashTableDelete(portal);
 
    /* reset portal */
    if (PointerIsValid(portal->cleanup))
        (*portal->cleanup) (portal);
 
-   PortalResetHeapMemory(portal);
-   MemoryContextFree((MemoryContext) &portal->variable,
-                     (Pointer) portal->name);
-   AllocSetReset(&portal->variable.setData);   /* XXX log */
-
-   /*
-    * In the case of a transaction abort it is possible that we get
-    * called while one of the memory contexts of the portal we're
-    * destroying is the current memory context.
-    *
-    * Don't know how to handle that cleanly because it is required to be in
-    * that context right now. This portal struct remains allocated in the
-    * PortalMemory context until backend dies.
-    *
-    * Not happy with that, but it's better to loose some bytes of memory
-    * than to have the backend dump core.
-    *
-    * --- Feb. 04, 1999 Jan Wieck
-    */
-   if (CurrentMemoryContext == (MemoryContext) PortalGetHeapMemory(portal))
-       return;
-   if (CurrentMemoryContext == (MemoryContext) PortalGetVariableMemory(portal))
-       return;
-
-   if (portal != BlankPortal)
-       MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
-}
-
-/* ----------------
- *     PortalResetHeapMemory
- *             Resets portal's heap memory context.
- *
- * Someday, Reset, Start, and End can be optimized by keeping a global
- * portal module stack of free HeapMemoryBlock's.  This will make Start
- * and End be fast.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadState if called when not in PortalHeapMemory context.
- *     BadArg if mode is invalid.
- * ----------------
- */
-void
-PortalResetHeapMemory(Portal portal)
-{
-   PortalHeapMemory context;
-   MemoryContext currentContext;
-
-   context = PortalGetHeapMemory(portal);
-
-   if (PointerIsValid(context->block))
-   {
-       /* save present context */
-       currentContext = MemoryContextSwitchTo((MemoryContext) context);
-
-       do
-       {
-           EndPortalAllocMode();
-       } while (PointerIsValid(context->block));
-
-       /* restore context */
-       MemoryContextSwitchTo(currentContext);
-   }
-}
-
-/*
- * StartPortalAllocMode
- *     Starts a new block of portal heap allocation using mode and limit;
- *     the current block is disabled until EndPortalAllocMode is called.
- *
- * Note:
- *     Note blocks may be stacked and restored arbitarily.
- *     The semantics of mode and limit are described in aset.h.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadState if called when not in PortalHeapMemory context.
- *     BadArg if mode is invalid.
- */
-void
-StartPortalAllocMode(AllocMode mode, Size limit)
-{
-   PortalHeapMemory context;
-
-   AssertState(PortalManagerEnabled);
-   AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
-   /* AssertArg(AllocModeIsValid); */
-
-   context = (PortalHeapMemory) CurrentMemoryContext;
-
-   /* stack current mode */
-   if (PointerIsValid(context->block))
-       FixedStackPush(&context->stackData, context->block);
-
-   /* allocate and initialize new block */
-   context->block = MemoryContextAlloc(
-             (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
-                                       sizeof(HeapMemoryBlockData));
-
-   /* XXX careful, context->block has never been stacked => bad state */
-
-   AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
-}
-
-/*
- * EndPortalAllocMode
- *     Ends current block of portal heap allocation; previous block is
- *     reenabled.
- *
- * Note:
- *     Note blocks may be stacked and restored arbitarily.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadState if called when not in PortalHeapMemory context.
- */
-void
-EndPortalAllocMode()
-{
-   PortalHeapMemory context;
+   /* release subsidiary storage */
+   MemoryContextDelete(PortalGetHeapMemory(portal));
 
-   AssertState(PortalManagerEnabled);
-   AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
-
-   context = (PortalHeapMemory) CurrentMemoryContext;
-   AssertState(PointerIsValid(context->block));        /* XXX Trap(...) */
-
-   /* free current mode */
-   AllocSetReset(&HEAPMEMBLOCK(context)->setData);
-   MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
-                     context->block);
-
-   /* restore previous mode */
-   context->block = FixedStackPop(&context->stackData);
-}
-
-/*
- * PortalGetVariableMemory
- *     Returns variable memory context for a given portal.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadArg if portal is invalid.
- */
-PortalVariableMemory
-PortalGetVariableMemory(Portal portal)
-{
-   return &portal->variable;
+   /* release name and portal data (both are in PortalMemory) */
+   pfree(portal->name);
+   pfree(portal);
 }
 
 /*
  * PortalGetHeapMemory
  *     Returns heap memory context for a given portal.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadArg if portal is invalid.
  */
-PortalHeapMemory
+MemoryContext
 PortalGetHeapMemory(Portal portal)
 {
-   return &portal->heap;
-}
-
-/*
- * PortalVariableMemoryGetPortal
- *     Returns portal containing given variable memory context.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadArg if context is invalid.
- */
-static Portal
-PortalVariableMemoryGetPortal(PortalVariableMemory context)
-{
-   return (Portal) ((char *) context - offsetof(PortalD, variable));
-}
-
-/*
- * PortalHeapMemoryGetPortal
- *     Returns portal containing given heap memory context.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadArg if context is invalid.
- */
-static Portal
-PortalHeapMemoryGetPortal(PortalHeapMemory context)
-{
-   return (Portal) ((char *) context - offsetof(PortalD, heap));
-}
-
-/*
- * PortalVariableMemoryGetHeapMemory
- *     Returns heap memory context associated with given variable memory.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadArg if context is invalid.
- */
-#ifdef NOT_USED
-PortalHeapMemory
-PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
-{
-   return ((PortalHeapMemory) ((char *) context
-                               - offsetof(PortalD, variable)
-                               +offsetof(PortalD, heap)));
-}
-
-#endif
-
-/*
- * PortalHeapMemoryGetVariableMemory
- *     Returns variable memory context associated with given heap memory.
- *
- * Exceptions:
- *     BadState if called when disabled.
- *     BadArg if context is invalid.
- */
-static PortalVariableMemory
-PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
-{
-   return ((PortalVariableMemory) ((char *) context
-                                   - offsetof(PortalD, heap)
-                                   +offsetof(PortalD, variable)));
+   return portal->heap;
 }
index b68ec2de5da6616341319f53828da6736ade6c25..8cb31889fa06eb8260eef5e41950e49f0d93512a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: command.h,v 1.18 2000/04/12 17:16:31 momjian Exp $
+ * $Id: command.h,v 1.19 2000/06/28 03:32:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,6 @@
 
 #include "utils/portal.h"
 
-extern MemoryContext PortalExecutorHeapMemory;
 
 /*
  * PerformPortalFetch
index 6b505cecdf02f1c460c46fcf38333aaec6f0cc3e..285bb314d3dd66895bad4fc079c7bf0e6241496d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hashjoin.h,v 1.16 2000/01/26 05:58:05 momjian Exp $
+ * $Id: hashjoin.h,v 1.17 2000/06/28 03:33:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *
  * Each active hashjoin has a HashJoinTable control block which is
  * palloc'd in the executor's context. All other storage needed for
- * the hashjoin is kept in a private "named portal", one for each hashjoin.
+ * the hashjoin is kept in private memory contexts, two for each hashjoin.
  * This makes it easy and fast to release the storage when we don't need it
  * anymore.
  *
- * The portal manager guarantees that portals will be discarded at end of
- * transaction, so we have no problem with a memory leak if the join is
+ * The contexts are made children of TransactionCommandContext, ensuring
+ * that they will be discarded at end of statement even if the join is
  * aborted early by an error.  (Likewise, any temporary files we make will
  * be cleaned up by the virtual file manager in event of an error.)
  *
  * Storage that should live through the entire join is allocated from the
- * portal's "variable context", while storage that is only wanted for the
- * current batch is allocated in the portal's "heap context".  By popping
- * the portal's heap at the end of a batch, we free all the per-batch storage
- * reliably and without tedium.
+ * "hashCxt", while storage that is only wanted for the current batch is
+ * allocated in the "batchCxt".  By resetting the batchCxt at the end of
+ * each batch, we free all the per-batch storage reliably and without tedium.
  * ----------------------------------------------------------------
  */
 
@@ -80,15 +79,6 @@ typedef struct HashTableData
     * to hash buckets and output.
     */
 
-   /*
-    * Ugly kluge: myPortal ought to be declared as type Portal (ie,
-    * PortalD*) but if we try to include utils/portal.h here, we end up
-    * with a circular dependency of include files!  Until the various
-    * node.h files are restructured in a cleaner way, we have to fake it.
-    * The most reliable fake seems to be to declare myPortal as void *
-    * and then cast it to the right things in nodeHash.c.
-    */
-   void       *myPortal;       /* where to keep working storage */
    MemoryContext hashCxt;      /* context for whole-hash-join storage */
    MemoryContext batchCxt;     /* context for this-batch-only storage */
 } HashTableData;
index 1c1e75876df41e511a7431e17b3727247db5abcb..2db0c5d5779634fa3ad439878eb7e4b2f6c1d62b 100644 (file)
@@ -28,7 +28,6 @@
 #include "utils/fcache.h"
 #include "utils/datum.h"
 #include "utils/syscache.h"
-#include "utils/portal.h"
 #include "utils/builtins.h"
 #include "catalog/pg_language.h"
 #include "access/heapam.h"
@@ -95,4 +94,6 @@ extern void *SPI_repalloc(void *pointer, Size size);
 extern void SPI_pfree(void *pointer);
 extern void SPI_freetuple(HeapTuple pointer);
 
+extern void AtEOXact_SPI(void);
+
 #endif  /* SPI_H */
index 916d7141d28d911995858f75a9c51af72fe59e6f..00b28a58037f6029cade46ba2f138c2f88459d0e 100644 (file)
@@ -3,7 +3,7 @@
  * spi.c
  *             Server Programming Interface private declarations
  *
- * $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.6 1999/07/15 15:21:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.7 2000/06/28 03:33:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,8 @@ typedef struct
    List       *qtlist;
    uint32      processed;      /* by Executor */
    SPITupleTable *tuptable;
-   Portal      portal;         /* portal per procedure */
+   MemoryContext procCxt;      /* procedure context */
+   MemoryContext execCxt;      /* executor context */
    MemoryContext savedcxt;
    CommandId   savedId;
 } _SPI_connection;
diff --git a/src/include/lib/fstack.h b/src/include/lib/fstack.h
deleted file mode 100644 (file)
index d639a22..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fstack.h
- *   Fixed format stack definitions.
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: fstack.h,v 1.9 2000/01/26 05:58:09 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-/*
- * Note:
- *     Fixed format stacks assist in the construction of FIFO stacks of
- *     fixed format structures.  Structures which are to be stackable
- *     should contain a FixedItemData component.  A stack is initilized
- *     with the offset of the FixedItemData component of the structure
- *     it will hold.  By doing so, push and pop operations are simplified
- *     for the callers.  All references to stackable items are pointers
- *     to the base of the structure instead of pointers to the
- *     FixedItemData component.
- *
- */
-#ifndef FSTACK_H
-#define FSTACK_H
-
-
-/*
- * FixedItem
- *     Fixed format stackable item chain component.
- *
- * Note:
- *     Structures must contain one FixedItemData component per stack in
- *     which it will be an item.
- */
-typedef struct FixedItemData FixedItemData;
-typedef FixedItemData *FixedItem;
-
-struct FixedItemData
-{
-   FixedItem   next;           /* next item or NULL */
-};
-
-/*
- * FixedStack
- *     Fixed format stack.
- */
-typedef struct FixedStackData
-{
-   FixedItem   top;            /* Top item on the stack or NULL */
-   Offset      offset;         /* Offset from struct base to item */
-   /* this could be signed short int! */
-} FixedStackData;
-
-typedef FixedStackData *FixedStack;
-
-/*
- * FixedStackInit
- *     Iniitializes stack for structures with given fixed component offset.
- *
- * Exceptions:
- *     BadArg if stack is invalid pointer.
- */
-extern void FixedStackInit(FixedStack stack, Offset offset);
-
-/*
- * FixedStackPop
- *     Returns pointer to top structure on stack or NULL if empty stack.
- *
- * Exceptions:
- *     BadArg if stack is invalid.
- */
-Pointer        FixedStackPop(FixedStack stack);
-
-/*
- * FixedStackPush
- *     Places structure associated with pointer onto top of stack.
- *
- * Exceptions:
- *     BadArg if stack is invalid.
- *     BadArg if pointer is invalid.
- */
-extern void FixedStackPush(FixedStack stack, Pointer pointer);
-
-/*
- * FixedStackGetTop
- *     Returns pointer to top structure of a stack.  This item is not poped.
- *
- * Note:
- *     This is not part of the normal stack interface.  It is intended for
- *      debugging use only.
- *
- * Exceptions:
- *     BadArg if stack is invalid.
- */
-extern Pointer FixedStackGetTop(FixedStack stack);
-
-/*
- * FixedStackGetNext
- *     Returns pointer to next structure after pointer of a stack.
- *
- * Note:
- *     This is not part of the normal stack interface.  It is intended for
- *      debugging use only.
- *
- * Exceptions:
- *     BadArg if stack is invalid.
- *     BadArg if pointer is invalid.
- *     BadArg if stack does not contain pointer.
- */
-extern Pointer FixedStackGetNext(FixedStack stack, Pointer pointer);
-
-#endif  /* FSTACK_H */
index 4ee039c0fee664914c3eb64a57096723f917129a..4a81af04eb80094361b44fd071b0bdd9a5c0d714 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqsignal.h,v 1.13 2000/06/15 00:52:11 momjian Exp $
+ * $Id: pqsignal.h,v 1.14 2000/06/28 03:33:14 tgl Exp $
  *
  * NOTES
  *   This shouldn't be in libpq, but the monitor and some other
 extern sigset_t UnBlockSig,
            BlockSig;
 
-#define PG_INITMASK()  ( \
-                           sigemptyset(&UnBlockSig), \
-                           sigfillset(&BlockSig) \
-                       )
 #define PG_SETMASK(mask)   sigprocmask(SIG_SETMASK, mask, NULL)
 #else
 extern int UnBlockSig,
            BlockSig;
 
-#define PG_INITMASK()  ( \
-                           UnBlockSig = 0, \
-                           BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) | \
-                                       sigmask(SIGTERM) | sigmask(SIGALRM) | \
-                                       sigmask(SIGINT) | sigmask(SIGUSR1) | \
-                                       sigmask(SIGUSR2) | sigmask(SIGCHLD) | \
-                                       sigmask(SIGWINCH) | sigmask(SIGFPE) \
-                       )
 #define PG_SETMASK(mask)   sigsetmask(*((int*)(mask)))
 #endif
 
 typedef void (*pqsigfunc) (int);
 
+extern void pqinitmask(void);
+
 extern pqsigfunc pqsignal(int signo, pqsigfunc func);
 
 #endif  /* PQSIGNAL_H */
index b3aa67250fcb4569148c91c70b3f9a580931732f..e6b8309aac840166d4b64515584d059d739f0821 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.60 2000/06/15 00:52:04 momjian Exp $
+ * $Id: miscadmin.h,v 1.61 2000/06/28 03:32:56 tgl Exp $
  *
  * NOTES
  *   some of the information in this file will be moved to
@@ -105,8 +105,6 @@ extern bool enableFsync;
 extern bool allowSystemTableMods;
 extern int SortMem;
 
-extern Oid LastOidProcessed;   /* for query rewrite */
-
 /* a few postmaster startup options are exported here so the
    configuration file processor has access to them */
 
@@ -189,9 +187,10 @@ typedef int16 ExitStatus;
 
 /* in utils/init/postinit.c */
 
-extern bool PostgresIsInitialized;
+extern int lockingOff;
 
 extern void InitPostgres(const char *dbname);
+extern void BaseInit(void);
 
 /* one of the ways to get out of here */
 #define ExitPostgres(status) proc_exec(status)
index 08ba9673181d6ed9d8d60a3d032d4c546aeda869..abc38e5c60d26ac22c52f70ff37e7139ed37aa0f 100644 (file)
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: memnodes.h,v 1.16 2000/01/26 05:58:16 momjian Exp $
+ * $Id: memnodes.h,v 1.17 2000/06/28 03:33:15 tgl Exp $
  *
- * XXX the typedefs in this file are different from the other ???nodes.h;
- *   they are pointers to structures instead of the structures themselves.
- *   If you're wondering, this is plain laziness. I don't want to touch
- *   the memory context code which should be revamped altogether some day.
- *                                                     - ay 10/94
  *-------------------------------------------------------------------------
  */
 #ifndef MEMNODES_H
 #define MEMNODES_H
 
-#include "lib/fstack.h"
 #include "nodes/nodes.h"
-#include "utils/memutils.h"
 
 /*
  * MemoryContext
  *     A logical context in which memory allocations occur.
  *
- * The types of memory contexts can be thought of as members of the
- * following inheritance hierarchy with properties summarized below.
+ * MemoryContext itself is an abstract type that can have multiple
+ * implementations, though for now we have only AllocSetContext.
+ * The function pointers in MemoryContextMethods define one specific
+ * implementation of MemoryContext --- they are a virtual function table
+ * in C++ terms.
  *
- *                     Node
- *                     |
- *             MemoryContext___
- *             /               \
- *     GlobalMemory    PortalMemoryContext
- *                     /               \
- *     PortalVariableMemory    PortalHeapMemory
+ * Node types that are actual implementations of memory contexts must
+ * begin with the same fields as MemoryContext.
  *
- *                     Flushed at      Flushed at      Checkpoints
- *                     Transaction     Portal
- *                     Commit          Close
- *
- * GlobalMemory                    n               n               n
- * PortalVariableMemory            n               y               n
- * PortalHeapMemory                y               y               y
+ * Note: for largely historical reasons, typedef MemoryContext is a pointer
+ * to the context struct rather than the struct type itself.
  */
 
-typedef struct MemoryContextMethodsData
+typedef struct MemoryContextMethods
 {
-   Pointer     (*alloc) ();
-   void        (*free_p) ();   /* need to use free as a #define, so can't
-                                * use free */
-   Pointer     (*realloc) ();
-   char       *(*getName) ();
-   void        (*dump) ();
-}         *MemoryContextMethods;
+   void       *(*alloc) (MemoryContext context, Size size);
+   /* call this free_p in case someone #define's free() */
+   void        (*free_p) (MemoryContext context, void *pointer);
+   void       *(*realloc) (MemoryContext context, void *pointer, Size size);
+   void        (*init) (MemoryContext context);
+   void        (*reset) (MemoryContext context);
+   void        (*delete) (MemoryContext context);
+   void        (*stats) (MemoryContext context);
+} MemoryContextMethods;
+
 
 typedef struct MemoryContextData
 {
-   NodeTag     type;
-   MemoryContextMethods method;
+   NodeTag     type;               /* identifies exact kind of context */
+   MemoryContextMethods *methods;  /* virtual function table */
+   MemoryContext parent;           /* NULL if no parent (toplevel context) */
+   MemoryContext firstchild;       /* head of linked list of children */
+   MemoryContext nextchild;        /* next child of same parent */
+   char       *name;               /* context name (just for debugging) */
 } MemoryContextData;
 
-/* utils/mcxt.h contains typedef struct MemoryContextData *MemoryContext */
+/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */
 
-/* think about doing this right some time but we'll have explicit fields
-   for now -ay 10/94 */
-typedef struct GlobalMemoryData
-{
-   NodeTag     type;
-   MemoryContextMethods method;
-   AllocSetData setData;
-   char       *name;
-   OrderedElemData elemData;
-} GlobalMemoryData;
 
-/* utils/mcxt.h contains typedef struct GlobalMemoryData *GlobalMemory */
-
-typedef struct MemoryContextData *PortalMemoryContext;
+/*
+ * AllocSetContext is our standard implementation of MemoryContext.
+ */
+typedef struct AllocBlockData *AllocBlock; /* internal to aset.c */
+typedef struct AllocChunkData *AllocChunk;
 
-typedef struct PortalVariableMemoryData
+typedef struct AllocSetContext
 {
-   NodeTag     type;
-   MemoryContextMethods method;
-   AllocSetData setData;
-}         *PortalVariableMemory;
+   MemoryContextData header;       /* Standard memory-context fields */
+   /* Info about storage allocated in this context: */
+   AllocBlock  blocks;             /* head of list of blocks in this set */
+#define ALLOCSET_NUM_FREELISTS 8
+   AllocChunk  freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
+   /* Allocation parameters for this context: */
+   Size        initBlockSize;      /* initial block size */
+   Size        maxBlockSize;       /* maximum block size */
+   AllocBlock  keeper;             /* if not NULL, keep this block
+                                    * over resets */
+} AllocSetContext;
 
-typedef struct PortalHeapMemoryData
-{
-   NodeTag     type;
-   MemoryContextMethods method;
-   Pointer     block;
-   FixedStackData stackData;
-}         *PortalHeapMemory;
 
 /*
  * MemoryContextIsValid
  *     True iff memory context is valid.
+ *
+ * Add new context types to the set accepted by this macro.
  */
 #define MemoryContextIsValid(context) \
-   (IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \
-    IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory))
+   ((context) != NULL && \
+    (IsA((context), AllocSetContext)))
+
 
 #endif  /* MEMNODES_H */
index 3be483177895c7445f05f24e480f54d817d9490b..481f61368807e0a29a254b8b6002d5ecbcf6be53 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.69 2000/06/18 22:44:31 tgl Exp $
+ * $Id: nodes.h,v 1.70 2000/06/28 03:33:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -122,10 +122,7 @@ typedef enum NodeTag
     *---------------------
     */
    T_MemoryContext = 400,
-   T_GlobalMemory,
-   T_PortalMemoryContext,
-   T_PortalVariableMemory,
-   T_PortalHeapMemory,
+   T_AllocSetContext,
 
    /*---------------------
     * TAGS FOR VALUE NODES (pg_list.h)
index bf65771529bf02a9a051409e2e16fe5739e4ca6d..1c6182f8d5f100f3bdf5956d1cc608e9959d85df 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geqo.h,v 1.19 2000/05/31 00:28:38 petere Exp $
+ * $Id: geqo.h,v 1.20 2000/06/28 03:33:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,7 +65,6 @@ extern int          Geqo_random_seed; /* or negative to use current time */
 extern RelOptInfo *geqo(Query *root);
 
 /* routines in geqo_eval.c */
-extern void geqo_eval_startup(void);
 extern Cost geqo_eval(Query *root, Gene *tour, int num_gene);
 extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count,
           int num_gene, RelOptInfo *old_rel);
index 0f26b7978a46c67e53173082bb861570d99a6033..a4a7fda1109f93b54fa69640c55b814d2afa97e0 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1995, Regents of the University of California
  *
- * $Id: postgres.h,v 1.41 2000/06/13 07:35:24 tgl Exp $
+ * $Id: postgres.h,v 1.42 2000/06/28 03:32:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,6 @@
 #include "postgres_ext.h"
 #include "c.h"
 #include "utils/elog.h"
-#include "utils/mcxt.h"
 #include "utils/palloc.h"
 
 /* ----------------------------------------------------------------
index 85eb424777f4a7c06f406aad5633283a9a0aed4e..35545f95191fab380f68e6d6e857507df8d2a8ee 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: shmem.h,v 1.22 2000/01/26 05:58:33 momjian Exp $
+ * $Id: shmem.h,v 1.23 2000/06/28 03:33:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,14 +63,13 @@ typedef struct SHM_QUEUE
 extern void ShmemIndexReset(void);
 extern void ShmemCreate(unsigned int key, unsigned int size);
 extern int InitShmem(unsigned int key, unsigned int size);
-extern long *ShmemAlloc(unsigned long size);
+extern void *ShmemAlloc(Size size);
 extern int ShmemIsValid(unsigned long addr);
 extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
              HASHCTL *infoP, int hash_flags);
 extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
 extern SHMEM_OFFSET ShmemPIDDestroy(int pid);
-extern long *ShmemInitStruct(char *name, unsigned long size,
-               bool *foundPtr);
+extern void *ShmemInitStruct(char *name, Size size, bool *foundPtr);
 
 
 typedef int TableID;
index 0dd1900a21064ea20b8d62a35f5a92a093a0becf..1bc5da9a3344d7f600eec030728a5558b9a4abc8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pquery.h,v 1.14 2000/01/26 05:58:35 momjian Exp $
+ * $Id: pquery.h,v 1.15 2000/06/28 03:33:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #define PQUERY_H
 
 #include "executor/execdesc.h"
+#include "utils/portal.h"
 
-/* moved to execdesc.h
-extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
-                                 CommandDest dest);
-
-*/
-extern EState *CreateExecutorState(void);
 
+extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
 
-extern void ProcessPortal(char *portalName, Query *parseTree,
-             Plan *plan, EState *state, TupleDesc attinfo,
-             CommandDest dest);
+extern EState *CreateExecutorState(void);
 
-extern void
-           ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
+extern Portal PreparePortal(char *portalName);
 
-#endif  /* pqueryIncluded */
+#endif  /* PQUERY_H */
index 6f7bdd6e4e7119bf81f6cb2b955e362268117009..cde0f5655a9d366bde32bf70db6f93d12e679cab 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tcopprot.h,v 1.30 2000/06/15 03:33:04 momjian Exp $
+ * $Id: tcopprot.h,v 1.31 2000/06/28 03:33:28 tgl Exp $
  *
  * OLD COMMENTS
  *   This file was created so that other c files could get the two
@@ -33,12 +33,11 @@ extern bool ShowPortNumber;
 #ifndef BOOTSTRAP_INCLUDE
 
 extern List *pg_parse_and_rewrite(char *query_string,
-                    Oid *typev, int nargs,
-                    bool aclOverride);
+                                 Oid *typev, int nargs);
 extern Plan *pg_plan_query(Query *querytree);
 extern void pg_exec_query_dest(char *query_string,
-                  CommandDest dest,
-                  bool aclOverride);
+                              CommandDest dest,
+                              MemoryContext parse_context);
 
 #endif  /* BOOTSTRAP_INCLUDE */
 
index b8e4ce71d769e391dd960479699b96e3ba4b3b48..cba400bc005cb92764dac55c51a1050f508294e9 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catcache.h,v 1.24 2000/06/17 04:56:29 tgl Exp $
+ * $Id: catcache.h,v 1.25 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,8 +75,10 @@ typedef struct catcache
 
 #define InvalidCatalogCacheId  (-1)
 
-extern GlobalMemory CacheCxt;
+/* this extern duplicates utils/memutils.h... */
+extern MemoryContext CacheMemoryContext;
 
+extern void CreateCacheMemoryContext(void);
 extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
                         ItemPointer pointer);
 extern void ResetSystemCache(void);
index ef243da145fc370db8851177aa9446103825c780..6d857175c94dd9bb5878f26324fdedce5ea9c262 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hsearch.h,v 1.15 2000/04/12 17:16:55 momjian Exp $
+ * $Id: hsearch.h,v 1.16 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,8 +84,7 @@ typedef struct htab
    char       *segbase;        /* segment base address for calculating
                                 * pointer values */
    SEG_OFFSET *dir;            /* 'directory' of segm starts */
-   long       *(*alloc) ();    /* memory allocator (long * for alignment
-                                * reasons) */
+   void       *(*alloc) (Size);    /* memory allocator */
 } HTAB;
 
 typedef struct hashctl
@@ -99,7 +98,7 @@ typedef struct hashctl
    long        max_dsize;      /* limit to dsize if directory size is
                                 * limited */
    long       *segbase;        /* base for calculating bucket + seg ptrs */
-   long       *(*alloc) ();    /* memory allocation function */
+   void       *(*alloc) (Size);    /* memory allocation function */
    long       *dir;            /* directory if allocated already */
    long       *hctl;           /* location of header information in shd
                                 * mem */
diff --git a/src/include/utils/mcxt.h b/src/include/utils/mcxt.h
deleted file mode 100644 (file)
index 7b867d8..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * mcxt.h
- *   POSTGRES memory context definitions.
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: mcxt.h,v 1.17 2000/05/21 02:23:28 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef MCXT_H
-#define MCXT_H
-
-/* These types are declared in nodes/memnodes.h, but most users of memory
- * allocation should just treat them as abstract types, so we do not provide
- * the struct contents here.
- */
-
-typedef struct MemoryContextData *MemoryContext;
-typedef struct GlobalMemoryData *GlobalMemory;
-
-
-extern DLLIMPORT MemoryContext CurrentMemoryContext;
-extern MemoryContext TopMemoryContext;
-
-
-/*
- * MaxAllocSize
- *     Arbitrary limit on size of allocations.
- *
- * Note:
- *     There is no guarantee that allocations smaller than MaxAllocSize
- *     will succeed.  Allocation requests larger than MaxAllocSize will
- *     be summarily denied.
- *
- *     This value should not be referenced except in one place in the code.
- *
- * XXX This should be defined in a file of tunable constants.
- */
-#define MaxAllocSize   (0xfffffff)     /* 16G - 1 */
-
-/*
- * prototypes for functions in mcxt.c
- */
-extern void EnableMemoryContext(bool on);
-extern Pointer MemoryContextAlloc(MemoryContext context, Size size);
-extern Pointer MemoryContextRealloc(MemoryContext context,
-                    Pointer pointer,
-                    Size size);
-extern void MemoryContextFree(MemoryContext context, Pointer pointer);
-extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
-extern GlobalMemory CreateGlobalMemory(char *name);
-extern void GlobalMemoryDestroy(GlobalMemory context);
-extern void GlobalMemoryStats(void);
-
-
-#endif  /* MCXT_H */
index 3e6ad2e53da223ab0772ee598bac8f57b2ae9f39..cbabdbf275efaf2866a23aa00ced6a076f89938f 100644 (file)
 /*-------------------------------------------------------------------------
  *
  * memutils.h
- *   this file contains general memory alignment, allocation
- *   and manipulation stuff that used to be spread out
- *   between the following files:
- *
- *     align.h                         alignment macros
- *     aset.h                          memory allocation set stuff
- *     oset.h                            (used by aset.h)
+ *   This file contains declarations for memory allocation utility
+ *   functions.  These are functions that are not quite widely used
+ *   enough to justify going in utils/palloc.h, but are still part
+ *   of the API of the memory management subsystem.
  *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: memutils.h,v 1.35 2000/05/21 02:23:28 tgl Exp $
+ * $Id: memutils.h,v 1.36 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef MEMUTILS_H
 #define MEMUTILS_H
 
-/* ----------------
- * Alignment macros: align a length or address appropriately for a given type.
- *
- * There used to be some incredibly crufty platform-dependent hackery here,
- * but now we rely on the configure script to get the info for us. Much nicer.
- *
- * NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
- * That case seems extremely unlikely to occur in practice, however.
- * ----------------
- */
+#include "nodes/memnodes.h"
 
-#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
-
-#define SHORTALIGN(LEN)            TYPEALIGN(ALIGNOF_SHORT, (LEN))
-#define INTALIGN(LEN)          TYPEALIGN(ALIGNOF_INT, (LEN))
-#define LONGALIGN(LEN)         TYPEALIGN(ALIGNOF_LONG, (LEN))
-#define DOUBLEALIGN(LEN)       TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
-#define MAXALIGN(LEN)          TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
-
-/*****************************************************************************
- *   oset.h --         Fixed format ordered set definitions.                *
- *****************************************************************************/
-/* Note:
- *     Fixed format ordered sets are .
- *     XXX This is a preliminary version.  Work is needed to explain
- *     XXX semantics of the external definitions.  Otherwise, the
- *     XXX functional interface should not change.
- *
- */
-
-typedef struct OrderedElemData OrderedElemData;
-typedef OrderedElemData *OrderedElem;
 
-typedef struct OrderedSetData OrderedSetData;
-typedef OrderedSetData *OrderedSet;
-
-struct OrderedElemData
-{
-   OrderedElem next;           /* Next elem or &this->set->dummy       */
-   OrderedElem prev;           /* Previous elem or &this->set->head    */
-   OrderedSet  set;            /* Parent set                           */
-};
-
-struct OrderedSetData
-{
-   OrderedElem head;           /* First elem or &this->dummy           */
-   OrderedElem dummy;          /* (hack) Terminator == NULL            */
-   OrderedElem tail;           /* Last elem or &this->head             */
-   Offset      offset;         /* Offset from struct base to elem      */
-   /* this could be signed short int! */
-};
-
-extern void OrderedSetInit(OrderedSet set, Offset offset);
-extern Pointer OrderedSetGetHead(OrderedSet set);
-extern Pointer OrderedElemGetPredecessor(OrderedElem elem);
-extern Pointer OrderedElemGetSuccessor(OrderedElem elem);
-extern void OrderedElemPop(OrderedElem elem);
-extern void OrderedElemPushInto(OrderedElem elem, OrderedSet Set);
-
-/*****************************************************************************
- *   aset.h --         Allocation set definitions.                          *
- *****************************************************************************/
 /*
- * Description:
- *     An allocation set is a set containing allocated elements.  When
- *     an allocation is requested for a set, memory is allocated and a
- *     pointer is returned.  Subsequently, this memory may be freed or
- *     reallocated.  In addition, an allocation set may be reset which
- *     will cause all memory allocated within it to be freed.
- *
- *     XXX The following material about allocation modes is all OUT OF DATE.
- *     aset.c currently implements only one allocation strategy,
- *     DynamicAllocMode, and that's the only one anyone ever requests anyway.
- *     If we ever did have more strategies, the new ones might or might
- *     not look like what is described here...
- *
- *     Allocations may occur in four different modes.  The mode of
- *     allocation does not affect the behavior of allocations except in
- *     terms of performance.  The allocation mode is set at the time of
- *     set initialization.  Once the mode is chosen, it cannot be changed
- *     unless the set is reinitialized.
- *
- *     "Dynamic" mode forces all allocations to occur in a heap.  This
- *     is a good mode to use when small memory segments are allocated
- *     and freed very frequently.  This is a good choice when allocation
- *     characteristics are unknown.  This is the default mode.
- *
- *     "Static" mode attempts to allocate space as efficiently as possible
- *     without regard to freeing memory.  This mode should be chosen only
- *     when it is known that many allocations will occur but that very
- *     little of the allocated memory will be explicitly freed.
- *
- *     "Tunable" mode is a hybrid of dynamic and static modes.  The
- *     tunable mode will use static mode allocation except when the
- *     allocation request exceeds a size limit supplied at the time of set
- *     initialization.  "Big" objects are allocated using dynamic mode.
- *
- *     "Bounded" mode attempts to allocate space efficiently given a limit
- *     on space consumed by the allocation set.  This restriction can be
- *     considered a "soft" restriction, because memory segments will
- *     continue to be returned after the limit is exceeded.  The limit is
- *     specified at the time of set initialization like for tunable mode.
+ * MaxAllocSize
+ *     Arbitrary limit on size of allocations.
  *
  * Note:
- *     Allocation sets are not automatically reset on a system reset.
- *     Higher level code is responsible for cleaning up.
+ *     There is no guarantee that allocations smaller than MaxAllocSize
+ *     will succeed.  Allocation requests larger than MaxAllocSize will
+ *     be summarily denied.
  *
- *     There may be other modes in the future.
+ * XXX This should be defined in a file of tunable constants.
  */
+#define MaxAllocSize   ((Size) 0xfffffff)      /* 16G - 1 */
 
-/*
- * AllocPointer
- *     Aligned pointer which may be a member of an allocation set.
- */
-typedef Pointer AllocPointer;
+#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
 
 /*
- * AllocMode
- *     Mode of allocation for an allocation set.
- *
- * Note:
- *     See above for a description of the various modes.
+ * All chunks allocated by any memory context manager are required to be
+ * preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
+ * A currently-allocated chunk must contain a backpointer to its owning
+ * context as well as the allocated size of the chunk.  The backpointer is
+ * used by pfree() and repalloc() to find the context to call.  The allocated
+ * size is not absolutely essential, but it's expected to be needed by any
+ * reasonable implementation.
  */
-typedef enum AllocMode
+typedef struct StandardChunkHeader
 {
-   DynamicAllocMode,           /* always dynamically allocate */
-   StaticAllocMode,            /* always "statically" allocate */
-   TunableAllocMode,           /* allocations are "tuned" */
-   BoundedAllocMode            /* allocations bounded to fixed usage */
-} AllocMode;
+   MemoryContext context;          /* owning context */
+   Size size;                      /* size of data space allocated in chunk */
+} StandardChunkHeader;
 
-#define DefaultAllocMode       DynamicAllocMode
+#define STANDARDCHUNKHEADERSIZE  MAXALIGN(sizeof(StandardChunkHeader))
 
-typedef struct AllocSetData *AllocSet;
-typedef struct AllocBlockData *AllocBlock;
-typedef struct AllocChunkData *AllocChunk;
-
-/*
- * AllocSet
- *     Allocation set.
- */
-typedef struct AllocSetData
-{
-   AllocBlock  blocks;         /* head of list of blocks in this set */
-#define ALLOCSET_NUM_FREELISTS 8
-   AllocChunk  freelist[ALLOCSET_NUM_FREELISTS];       /* free chunk lists */
-   /* Note: this will change in the future to support other modes */
-} AllocSetData;
 
 /*
- * AllocBlock
- *     An AllocBlock is the unit of memory that is obtained by aset.c
- *     from malloc().  It contains one or more AllocChunks, which are
- *     the units requested by palloc() and freed by pfree().  AllocChunks
- *     cannot be returned to malloc() individually, instead they are put
- *     on freelists by pfree() and re-used by the next palloc() that has
- *     a matching request size.
+ * Standard top-level memory contexts.
  *
- *     AllocBlockData is the header data for a block --- the usable space
- *     within the block begins at the next alignment boundary.
+ * Only TopMemoryContext and ErrorContext are initialized by
+ * MemoryContextInit() itself.
  */
-typedef struct AllocBlockData
-{
-   AllocSet    aset;           /* aset that owns this block */
-   AllocBlock  next;           /* next block in aset's blocks list */
-   char       *freeptr;        /* start of free space in this block */
-   char       *endptr;         /* end of space in this block */
-} AllocBlockData;
+extern MemoryContext TopMemoryContext;
+extern MemoryContext ErrorContext;
+extern MemoryContext PostmasterContext;
+extern MemoryContext CacheMemoryContext;
+extern MemoryContext QueryContext;
+extern MemoryContext TopTransactionContext;
+extern MemoryContext TransactionCommandContext;
 
-/*
- * AllocChunk
- *     The prefix of each piece of memory in an AllocBlock
- */
-typedef struct AllocChunkData
-{
-   /* aset is the owning aset if allocated, or the freelist link if free */
-   void       *aset;
-   /* size is always the size of the usable space in the chunk */
-   Size        size;
-} AllocChunkData;
 
 /*
- * AllocPointerIsValid
- *     True iff pointer is valid allocation pointer.
+ * Memory-context-type-independent functions in mcxt.c
  */
-#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
+extern void MemoryContextInit(void);
+extern void MemoryContextReset(MemoryContext context);
+extern void MemoryContextDelete(MemoryContext context);
+extern void MemoryContextResetChildren(MemoryContext context);
+extern void MemoryContextDeleteChildren(MemoryContext context);
+extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
+extern void MemoryContextStats(MemoryContext context);
+extern bool MemoryContextContains(MemoryContext context, void *pointer);
 
 /*
- * AllocSetIsValid
- *     True iff set is valid allocation set.
+ * This routine handles the context-type-independent part of memory
+ * context creation.  It's intended to be called from context-type-
+ * specific creation routines, and noplace else.
  */
-#define AllocSetIsValid(set) PointerIsValid(set)
+extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
+                                        MemoryContextMethods *methods,
+                                        MemoryContext parent,
+                                        const char *name);
 
-extern void AllocSetInit(AllocSet set, AllocMode mode, Size limit);
 
-extern void AllocSetReset(AllocSet set);
+/*
+ * Memory-context-type-specific functions
+ */
 
-extern bool AllocSetContains(AllocSet set, AllocPointer pointer);
-extern AllocPointer AllocSetAlloc(AllocSet set, Size size);
-extern void AllocSetFree(AllocSet set, AllocPointer pointer);
-extern AllocPointer AllocSetRealloc(AllocSet set, AllocPointer pointer,
-               Size size);
+/* aset.c */
+extern MemoryContext AllocSetContextCreate(MemoryContext parent,
+                                          const char *name,
+                                          Size minContextSize,
+                                          Size initBlockSize,
+                                          Size maxBlockSize);
 
-extern void AllocSetDump(AllocSet set);
-extern void AllocSetStats(AllocSet set, const char *ident);
+/*
+ * 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_INITSIZE  (8 * 1024)
+#define ALLOCSET_DEFAULT_MAXSIZE   (8 * 1024 * 1024)
 
 
 #endif  /* MEMUTILS_H */
diff --git a/src/include/utils/module.h b/src/include/utils/module.h
deleted file mode 100644 (file)
index e7e4558..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * module.h
- *   this file contains general "module" stuff  that used to be
- *   spread out between the following files:
- *
- *     enbl.h                  module enable stuff
- *     trace.h                 module trace stuff (now gone)
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: module.h,v 1.6 2000/01/26 05:58:38 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef MODULE_H
-#define MODULE_H
-
-/*
- * prototypes for functions in init/enbl.c
- */
-extern bool BypassEnable(int *enableCountInOutP, bool on);
-
-#endif  /* MODULE_H */
index 0ec6caabbbd25209854548c82abc49732e4afdbe..4bfdedff7e393d561759802ebc2ad3fdc5baf158 100644 (file)
@@ -3,36 +3,85 @@
  * palloc.h
  *   POSTGRES memory allocator definitions.
  *
+ * This file contains the basic memory allocation interface that is
+ * needed by almost every backend module.  It is included directly by
+ * postgres.h, so the definitions here are automatically available
+ * everywhere.  Keep it lean!
+ *
+ * Memory allocation occurs within "contexts".  Every chunk obtained from
+ * palloc()/MemoryContextAlloc() is allocated within a specific context.
+ * The entire contents of a context can be freed easily and quickly by
+ * resetting or deleting the context --- this is both faster and less
+ * prone to memory-leakage bugs than releasing chunks individually.
+ * We organize contexts into context trees to allow fine-grain control
+ * over chunk lifetime while preserving the certainty that we will free
+ * everything that should be freed.  See utils/mmgr/README for more info.
+ *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: palloc.h,v 1.12 2000/01/26 05:58:38 momjian Exp $
+ * $Id: palloc.h,v 1.13 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef PALLOC_H
 #define PALLOC_H
 
-#ifdef PALLOC_IS_MALLOC
+/*
+ * Type MemoryContextData is declared in nodes/memnodes.h.  Most users
+ * of memory allocation should just treat it as an abstract type, so we
+ * do not provide the struct contents here.
+ */
+typedef struct MemoryContextData *MemoryContext;
+
+/*
+ * CurrentMemoryContext is the default allocation context for palloc().
+ * We declare it here so that palloc() can be a macro.  Avoid accessing it
+ * directly!  Instead, use MemoryContextSwitchTo() to change the setting.
+ */
+extern DLLIMPORT MemoryContext CurrentMemoryContext;
+
+/*
+ * Fundamental memory-allocation operations (more are in utils/memutils.h)
+ */
+extern void *MemoryContextAlloc(MemoryContext context, Size size);
+
+#define palloc(sz)  MemoryContextAlloc(CurrentMemoryContext, (sz))
 
-#define palloc(s)    malloc(s)
-#define pfree(p)     free(p)
-#define repalloc(p,s) realloc((p),(s))
+extern void pfree(void *pointer);
 
-#else                          /* ! PALLOC_IS_MALLOC */
+extern void *repalloc(void *pointer, Size size);
 
-/* ----------
- * In the case we use memory contexts, use macro's for palloc() etc.
- * ----------
+extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
+
+/*
+ * These are like standard strdup() except the copied string is
+ * allocated in a context, not with malloc().
+ */
+extern char *MemoryContextStrdup(MemoryContext context, const char *string);
+
+#define pstrdup(str)  MemoryContextStrdup(CurrentMemoryContext, (str))
+
+
+/* ----------------
+ * Alignment macros: align a length or address appropriately for a given type.
+ *
+ * There used to be some incredibly crufty platform-dependent hackery here,
+ * but now we rely on the configure script to get the info for us. Much nicer.
+ *
+ * NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
+ * That case seems extremely unlikely to occur in practice, however.
+ * ----------------
  */
-#define palloc(s)    ((void *)MemoryContextAlloc(CurrentMemoryContext,(Size)(s)))
-#define pfree(p)     MemoryContextFree(CurrentMemoryContext,(Pointer)(p))
-#define repalloc(p,s) ((void *)MemoryContextRealloc(CurrentMemoryContext,(Pointer)(p),(Size)(s)))
 
-#endif  /* PALLOC_IS_MALLOC */
+#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
+
+#define SHORTALIGN(LEN)            TYPEALIGN(ALIGNOF_SHORT, (LEN))
+#define INTALIGN(LEN)          TYPEALIGN(ALIGNOF_INT, (LEN))
+#define LONGALIGN(LEN)         TYPEALIGN(ALIGNOF_LONG, (LEN))
+#define DOUBLEALIGN(LEN)       TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
+#define MAXALIGN(LEN)          TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
 
-/* like strdup except uses palloc */
-extern char *pstrdup(const char *pointer);
 
 #endif  /* PALLOC_H */
index 406fcc6af2353747b40e937d0261b5add799a183..bb240fe599dac377a400458fc51c25e0898cc5cb 100644 (file)
@@ -7,16 +7,14 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: portal.h,v 1.23 2000/04/12 17:16:55 momjian Exp $
+ * $Id: portal.h,v 1.24 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * Note:
  *     A portal is an abstraction which represents the execution state of
- * a running query (or a fixed sequence of queries).  The "blank portal" is
- * a portal with an InvalidName.  This blank portal is in existance except
- * between calls to BlankPortalAssignName and GetPortalByName(NULL).
+ * a running query (or a fixed sequence of queries).
  *
  * Note:
  *     now that PQ calls can be made from within a backend, a portal
 #include "executor/execdesc.h"
 #include "nodes/memnodes.h"
 
-typedef struct PortalBlockData
-{
-   AllocSetData setData;
-   FixedItemData itemData;
-} PortalBlockData;
-
-typedef PortalBlockData *PortalBlock;
 
-typedef struct PortalD PortalD;
-typedef PortalD *Portal;
+typedef struct PortalD *Portal;
 
-struct PortalD
+typedef struct PortalD
 {
-   char       *name;           /* XXX PortalName */
-   struct PortalVariableMemoryData variable;
-   struct PortalHeapMemoryData heap;
-   QueryDesc  *queryDesc;
+   char       *name;           /* Portal's name */
+   MemoryContext heap;         /* subsidiary memory */
+   QueryDesc  *queryDesc;      /* Info about query associated with portal */
    TupleDesc   attinfo;
    EState     *state;
-   void        (*cleanup) (Portal);
-};
+   void        (*cleanup) (Portal); /* Cleanup routine (optional) */
+} PortalD;
 
 /*
  * PortalIsValid
@@ -57,36 +46,20 @@ struct PortalD
  */
 #define PortalIsValid(p) PointerIsValid(p)
 
-/*
- * Special portals (well, their names anyway)
- */
-#define VACPNAME       ""
-#define TRUNCPNAME             ""
-
-extern bool PortalNameIsSpecial(char *pname);
+extern void EnablePortalManager(void);
 extern void AtEOXact_portals(void);
-extern void EnablePortalManager(bool on);
+extern Portal CreatePortal(char *name);
+extern void PortalDrop(Portal *portalP);
 extern Portal GetPortalByName(char *name);
-extern Portal BlankPortalAssignName(char *name);
 extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
               TupleDesc attinfo, EState *state,
               void (*cleanup) (Portal portal));
 extern QueryDesc *PortalGetQueryDesc(Portal portal);
 extern EState *PortalGetState(Portal portal);
-extern Portal CreatePortal(char *name);
-extern void PortalDrop(Portal *portalP);
-extern void StartPortalAllocMode(AllocMode mode, Size limit);
-extern void EndPortalAllocMode(void);
-extern void PortalResetHeapMemory(Portal portal);
-extern PortalVariableMemory PortalGetVariableMemory(Portal portal);
-extern PortalHeapMemory PortalGetHeapMemory(Portal portal);
-extern void CommonSpecialPortalOpen(void);
-extern void CommonSpecialPortalClose(void);
-extern PortalVariableMemory CommonSpecialPortalGetMemory(void);
-extern bool CommonSpecialPortalIsOpen(void);
+extern MemoryContext PortalGetHeapMemory(Portal portal);
 
 /* estimate of the maximum number of open portals a user would have,
- * used in initially sizing the PortalHashTable in EnablePortalManager()
+ * used in initially sizing the PortalHashTable in EnablePortalManager()
  */
 #define PORTALS_PER_USER      10