From 1aebc3618a0be13451918581ad390ad9a3518702 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Wed, 28 Jun 2000 03:33:33 +0000 Subject: [PATCH] First phase of memory management rewrite (see backend/utils/mmgr/README 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. --- doc/src/sgml/geqo.sgml | 18 +- doc/src/sgml/ref/declare.sgml | 9 +- src/backend/Makefile | 4 +- src/backend/access/heap/heapam.c | 5 +- src/backend/access/transam/xact.c | 238 ++++--- src/backend/bootstrap/bootstrap.c | 40 +- src/backend/catalog/heap.c | 32 +- src/backend/catalog/index.c | 18 +- src/backend/catalog/pg_proc.c | 5 +- src/backend/commands/command.c | 66 +- src/backend/commands/indexcmds.c | 35 +- src/backend/commands/trigger.c | 39 +- src/backend/commands/user.c | 4 +- src/backend/commands/vacuum.c | 110 +-- src/backend/executor/functions.c | 6 +- src/backend/executor/nodeAgg.c | 10 +- src/backend/executor/nodeHash.c | 50 +- src/backend/executor/spi.c | 166 ++--- src/backend/lib/Makefile | 4 +- src/backend/lib/fstack.c | 145 ---- src/backend/lib/stringinfo.c | 15 +- src/backend/libpq/be-fsstubs.c | 41 +- src/backend/libpq/be-pqexec.c | 6 +- src/backend/libpq/pqsignal.c | 40 +- src/backend/optimizer/geqo/geqo_eval.c | 67 +- src/backend/optimizer/geqo/geqo_main.c | 5 +- src/backend/postmaster/postmaster.c | 46 +- src/backend/rewrite/rewriteDefine.c | 113 +-- src/backend/rewrite/rewriteSupport.c | 10 +- src/backend/storage/ipc/shmem.c | 47 +- src/backend/storage/large_object/inv_api.c | 4 +- src/backend/storage/lmgr/lock.c | 33 +- src/backend/storage/lmgr/proc.c | 12 +- src/backend/storage/smgr/md.c | 46 +- src/backend/tcop/postgres.c | 240 ++++--- src/backend/tcop/pquery.c | 178 ++--- src/backend/utils/cache/catcache.c | 91 ++- src/backend/utils/cache/relcache.c | 25 +- src/backend/utils/cache/temprel.c | 8 +- src/backend/utils/error/elog.c | 61 +- src/backend/utils/fmgr/dfmgr.c | 4 +- src/backend/utils/hash/dynahash.c | 54 +- src/backend/utils/init/Makefile | 5 +- src/backend/utils/init/enbl.c | 47 -- src/backend/utils/init/postinit.c | 23 +- src/backend/utils/mb/conv.c | 29 +- src/backend/utils/mmgr/Makefile | 4 +- src/backend/utils/mmgr/README | 379 ++++++++++ src/backend/utils/mmgr/aset.c | 365 +++++++--- src/backend/utils/mmgr/mcxt.c | 760 ++++++++++----------- src/backend/utils/mmgr/oset.c | 165 ----- src/backend/utils/mmgr/palloc.c | 41 -- src/backend/utils/mmgr/portalmem.c | 741 ++------------------ src/include/commands/command.h | 3 +- src/include/executor/hashjoin.h | 24 +- src/include/executor/spi.h | 3 +- src/include/executor/spi_priv.h | 5 +- src/include/lib/fstack.h | 115 ---- src/include/libpq/pqsignal.h | 16 +- src/include/miscadmin.h | 7 +- src/include/nodes/memnodes.h | 112 ++- src/include/nodes/nodes.h | 7 +- src/include/optimizer/geqo.h | 3 +- src/include/postgres.h | 3 +- src/include/storage/shmem.h | 7 +- src/include/tcop/pquery.h | 19 +- src/include/tcop/tcopprot.h | 9 +- src/include/utils/catcache.h | 6 +- src/include/utils/hsearch.h | 7 +- src/include/utils/mcxt.h | 60 -- src/include/utils/memutils.h | 252 ++----- src/include/utils/module.h | 26 - src/include/utils/palloc.h | 79 ++- src/include/utils/portal.h | 55 +- 74 files changed, 2278 insertions(+), 3249 deletions(-) delete mode 100644 src/backend/lib/fstack.c delete mode 100644 src/backend/utils/init/enbl.c create mode 100644 src/backend/utils/mmgr/README delete mode 100644 src/backend/utils/mmgr/oset.c delete mode 100644 src/backend/utils/mmgr/palloc.c delete mode 100644 src/include/lib/fstack.h delete mode 100644 src/include/utils/mcxt.h delete mode 100644 src/include/utils/module.h diff --git a/doc/src/sgml/geqo.sgml b/doc/src/sgml/geqo.sgml index fd6d58aca0..4f2f80e97a 100644 --- a/doc/src/sgml/geqo.sgml +++ b/doc/src/sgml/geqo.sgml @@ -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> diff --git a/doc/src/sgml/ref/declare.sgml b/doc/src/sgml/ref/declare.sgml index c3c8b52680..803949a1ea 100644 --- a/doc/src/sgml/ref/declare.sgml +++ b/doc/src/sgml/ref/declare.sgml @@ -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> diff --git a/src/backend/Makefile b/src/backend/Makefile index 37a4a7bae9..ab691cef46 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -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 \ diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index aacef2a66a..7ca83587a4 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -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); diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index d6551cc9c9..bc8f968571 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -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: @@ -18,14 +18,14 @@ * * 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 @@ -42,6 +42,15 @@ * * 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. @@ -151,13 +160,15 @@ #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 diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index b49d5ef8bf..54d4ab8139 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -34,14 +34,14 @@ #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); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 7aeec8adb0..9ba935f716 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -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? * ---------------- */ diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5b8e005c5f..c737618996 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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 diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 836790c82a..e6091f6f63 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -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); } diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 5644afc46c..d0bd89fdfd 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -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. @@ -40,13 +36,6 @@ #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 * ---------------- diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index e5896b304c..bb45f01f67 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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); } diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 62d88caf39..fbb5a694b8 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.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); diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 859cb31eda..9bb36311cc 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -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 $ * *------------------------------------------------------------------------- */ diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 5eed27387a..01ed68b3b7 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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) diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index ee5fabf170..6d8d93a47f 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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) { diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index c9d6299f49..0289cf45bd 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -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)); } /* --------------------------------------- diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index b662883803..34b0a269a5 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -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 * */ @@ -23,11 +23,12 @@ #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 diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index ac86695ee1..1ab6ae67d5 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -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; diff --git a/src/backend/lib/Makefile b/src/backend/lib/Makefile index 6b8a9d7202..428935f255 100644 --- a/src/backend/lib/Makefile +++ b/src/backend/lib/Makefile @@ -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 index 9552909bc0..0000000000 --- a/src/backend/lib/fstack.c +++ /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); -} diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c index 4f2df74684..379cd79502 100644 --- a/src/backend/lib/stringinfo.c +++ b/src/backend/lib/stringinfo.c @@ -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; } diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index a12ae3a8a8..75f6562a8f 100644 --- a/src/backend/libpq/be-fsstubs.c +++ b/src/backend/libpq/be-fsstubs.c @@ -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, @@ -24,8 +24,10 @@ * 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; } diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c index 42d48281e0..c76889a7a7 100644 --- a/src/backend/libpq/be-pqexec.c +++ b/src/backend/libpq/be-pqexec.c @@ -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 diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c index 04ebd7dd57..4648fe455f 100644 --- a/src/backend/libpq/pqsignal.c +++ b/src/backend/libpq/pqsignal.c @@ -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 @@ -44,6 +44,44 @@ #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) { diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c index f3e009f5d1..fa46fac6c8 100644 --- a/src/backend/optimizer/geqo/geqo_eval.c +++ b/src/backend/optimizer/geqo/geqo_eval.c @@ -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 @@ -33,41 +33,8 @@ #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; } diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c index b00e9823bd..4f2f63572c 100644 --- a/src/backend/optimizer/geqo/geqo_main.c +++ b/src/backend/optimizer/geqo/geqo_main.c @@ -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); diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index f712d7cfec..135b6d5950 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -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 (", diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 40ebf3e02c..08351fe669 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -16,51 +16,20 @@ #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; } /* diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c index 9a5f486241..113e0b73c5 100644 --- a/src/backend/rewrite/rewriteSupport.c +++ b/src/backend/rewrite/rewriteSupport.c @@ -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) diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 8b7ad3874b..4c590a2774 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -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 */ diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index 474f2616aa..5ca3b7e826 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -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)); diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index d18739497b..12a8372c7c 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -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); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index ed41e43727..de2b406f87 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -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; diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 19433ae29a..de51e703f8 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -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; diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 9209b6509f..e018114a5d 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -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 diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index b26923b6f1..9e52930e20 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -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); -} diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index a1c2d5b7bb..d673000678 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -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 diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index a063534c0d..b0ee20fce9 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.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); diff --git a/src/backend/utils/cache/temprel.c b/src/backend/utils/cache/temprel.c index d09e35336e..20c94ac57b 100644 --- a/src/backend/utils/cache/temprel.c +++ b/src/backend/utils/cache/temprel.c @@ -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; diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 5b05b81a18..da8d80763a 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -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; } } diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index ca9b01a8c4..baa89be7bb 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -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); diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index 93707fcba9..9646a7c550 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -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; diff --git a/src/backend/utils/init/Makefile b/src/backend/utils/init/Makefile index 60ee275c64..9e3e3e9d42 100644 --- a/src/backend/utils/init/Makefile +++ b/src/backend/utils/init/Makefile @@ -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 index 137653e31a..0000000000 --- a/src/backend/utils/init/enbl.c +++ /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); -} diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 51cab6f0e8..f2a5864666 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -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 */ } diff --git a/src/backend/utils/mb/conv.c b/src/backend/utils/mb/conv.c index 7ee42f0e33..af7f5623b5 100644 --- a/src/backend/utils/mb/conv.c +++ b/src/backend/utils/mb/conv.c @@ -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 diff --git a/src/backend/utils/mmgr/Makefile b/src/backend/utils/mmgr/Makefile index 4769817222..371f976781 100644 --- a/src/backend/utils/mmgr/Makefile +++ b/src/backend/utils/mmgr/Makefile @@ -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 index 0000000000..1b82d6398c --- /dev/null +++ b/src/backend/utils/mmgr/README @@ -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. diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 574b98697d..e0244ade78 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -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 @@ -30,15 +33,68 @@ * 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), @@ -59,9 +115,9 @@ /* 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; @@ -74,20 +130,21 @@ * 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) \ @@ -95,6 +152,29 @@ #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); } diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 5a3be6700e..71877c4e62 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -17,41 +23,8 @@ #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 index 86487ab07d..0000000000 --- a/src/backend/utils/mmgr/oset.c +++ /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 index e714225be9..0000000000 --- a/src/backend/utils/mmgr/palloc.c +++ /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; -} diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index 71e94b7096..21aeb0a8a5 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -40,67 +40,28 @@ * * 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; } diff --git a/src/include/commands/command.h b/src/include/commands/command.h index b68ec2de5d..8cb31889fa 100644 --- a/src/include/commands/command.h +++ b/src/include/commands/command.h @@ -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 diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h index 6b505cecdf..285bb314d3 100644 --- a/src/include/executor/hashjoin.h +++ b/src/include/executor/hashjoin.h @@ -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 $ * *------------------------------------------------------------------------- */ @@ -22,20 +22,19 @@ * * 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; diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 1c1e75876d..2db0c5d577 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -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 */ diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h index 916d7141d2..00b28a5803 100644 --- a/src/include/executor/spi_priv.h +++ b/src/include/executor/spi_priv.h @@ -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 index d639a224fc..0000000000 --- a/src/include/lib/fstack.h +++ /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 */ diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h index 4ee039c0fe..4a81af04eb 100644 --- a/src/include/libpq/pqsignal.h +++ b/src/include/libpq/pqsignal.h @@ -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 @@ -24,28 +24,18 @@ 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 */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index b3aa67250f..e6b8309aac 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -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) diff --git a/src/include/nodes/memnodes.h b/src/include/nodes/memnodes.h index 08ba967318..abc38e5c60 100644 --- a/src/include/nodes/memnodes.h +++ b/src/include/nodes/memnodes.h @@ -7,100 +7,88 @@ * 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 */ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 3be4831778..481f613688 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -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) diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h index bf65771529..1c6182f8d5 100644 --- a/src/include/optimizer/geqo.h +++ b/src/include/optimizer/geqo.h @@ -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); diff --git a/src/include/postgres.h b/src/include/postgres.h index 0f26b7978a..a4a7fda110 100644 --- a/src/include/postgres.h +++ b/src/include/postgres.h @@ -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" /* ---------------------------------------------------------------- diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h index 85eb424777..35545f9519 100644 --- a/src/include/storage/shmem.h +++ b/src/include/storage/shmem.h @@ -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; diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h index 0dd1900a21..1bc5da9a33 100644 --- a/src/include/tcop/pquery.h +++ b/src/include/tcop/pquery.h @@ -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 $ * *------------------------------------------------------------------------- */ @@ -15,20 +15,13 @@ #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 */ diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 6f7bdd6e4e..cde0f5655a 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -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 */ diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h index b8e4ce71d7..cba400bc00 100644 --- a/src/include/utils/catcache.h +++ b/src/include/utils/catcache.h @@ -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); diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h index ef243da145..6d857175c9 100644 --- a/src/include/utils/hsearch.h +++ b/src/include/utils/hsearch.h @@ -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 index 7b867d8664..0000000000 --- a/src/include/utils/mcxt.h +++ /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 */ diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 3e6ad2e53d..cbabdbf275 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -1,230 +1,114 @@ /*------------------------------------------------------------------------- * * 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 index e7e45580ac..0000000000 --- a/src/include/utils/module.h +++ /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 */ diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 0ec6caabbb..4bfdedff7e 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -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 */ diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h index 406fcc6af2..bb240fe599 100644 --- a/src/include/utils/portal.h +++ b/src/include/utils/portal.h @@ -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 @@ -29,27 +27,18 @@ #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 -- 2.40.0