]> granicus.if.org Git - postgresql/commitdiff
First phase of memory management rewrite (see backend/utils/mmgr/README
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 28 Jun 2000 03:33:33 +0000 (03:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.9 2000/03/31 03:27:40 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.10 2000/06/28 03:30:53 tgl Exp $
 Genetic Optimizer
 -->
 
@@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer
 <Sect2>
 <Title>Basic Improvements</Title>
 
-<Sect3>
-<Title>Improve freeing of memory when query is already processed</Title>
-
-<Para>
-With large <Command>join</Command> queries the computing time spent for the genetic query
-optimization seems to be a mere <Emphasis>fraction</Emphasis> of the time
- <ProductName>Postgres</ProductName>
-needs for freeing memory via routine <Function>MemoryContextFree</Function>,
-file <FileName>backend/utils/mmgr/mcxt.c</FileName>.
-Debugging showed that it get stucked in a loop of routine
-<Function>OrderedElemPop</Function>, file <FileName>backend/utils/mmgr/oset.c</FileName>.
-The same problems arise with long queries when using the normal
-<ProductName>Postgres</ProductName> query optimization algorithm.
-</para>
-</sect3>
-
 <Sect3>
 <Title>Improve genetic algorithm parameter settings</Title>
 
index c3c8b526807bb6eaeaa44dc950baf3f033210228..803949a1eaaf6447240d350267f211e822f6e129 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.8 1999/12/30 22:58:10 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.9 2000/06/28 03:30:54 tgl Exp $
 Postgres documentation
 -->
 
@@ -153,12 +153,13 @@ SELECT
 
      <varlistentry>
       <term><computeroutput>
-NOTICE
-BlankPortalAssignName: portal "<replaceable class="parameter">cursorname</replaceable>" already exists
+NOTICE:  Closing pre-existing portal "<replaceable class="parameter">cursorname</replaceable>"
        </computeroutput></term>
       <listitem>
        <para>
-       This error occurs if <replaceable class="parameter">cursorname</replaceable> 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.
        </para>
       </listitem>
      </varlistentry>
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 <math.h>
 
 #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, "<hashtable %d>", 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 manager>");
-       _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 %d>", _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 <math.h>
-
 #include "postgres.h"
+
+#include <math.h>
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #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       "<geqo workspace>"
-       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 <sys/time.h>
 #include <unistd.h>
@@ -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 <sys/time.h>
 #include <ctype.h>
 #ifdef ENABLE_SYSLOG
-# include <syslog.h>
+#include <syslog.h>
 #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 <EXPLAIN>.
- *             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               "<vacuum>"
-#define TRUNCPNAME                             "<truncate>"
-
-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