Commit 1aebc361 authored by Tom Lane's avatar Tom Lane

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.
parent b601c8d8
<!-- <!--
$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 Genetic Optimizer
--> -->
...@@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer ...@@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer
<Sect2> <Sect2>
<Title>Basic Improvements</Title> <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> <Sect3>
<Title>Improve genetic algorithm parameter settings</Title> <Title>Improve genetic algorithm parameter settings</Title>
......
<!-- <!--
$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 Postgres documentation
--> -->
...@@ -153,12 +153,13 @@ SELECT ...@@ -153,12 +153,13 @@ SELECT
<varlistentry> <varlistentry>
<term><computeroutput> <term><computeroutput>
NOTICE NOTICE: Closing pre-existing portal "<replaceable class="parameter">cursorname</replaceable>"
BlankPortalAssignName: portal "<replaceable class="parameter">cursorname</replaceable>" already exists
</computeroutput></term> </computeroutput></term>
<listitem> <listitem>
<para> <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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
# #
# #
# IDENTIFICATION # 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 ...@@ -237,8 +237,6 @@ install-headers: prebuildheaders $(SRCDIR)/include/config.h
$(HEADERDIR)/utils/fmgroids.h $(HEADERDIR)/utils/fmgroids.h
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \ $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \
$(HEADERDIR)/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 \ $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/access/attnum.h \
$(HEADERDIR)/access/attnum.h $(HEADERDIR)/access/attnum.h
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \ $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -1230,10 +1230,7 @@ heap_insert(Relation relation, HeapTuple tup) ...@@ -1230,10 +1230,7 @@ heap_insert(Relation relation, HeapTuple tup)
* ---------------- * ----------------
*/ */
if (!OidIsValid(tup->t_data->t_oid)) if (!OidIsValid(tup->t_data->t_oid))
{
tup->t_data->t_oid = newoid(); tup->t_data->t_oid = newoid();
LastOidProcessed = tup->t_data->t_oid;
}
else else
CheckMaxObjectId(tup->t_data->t_oid); CheckMaxObjectId(tup->t_data->t_oid);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Transaction aborts can now occur two ways: * Transaction aborts can now occur two ways:
...@@ -18,14 +18,14 @@ ...@@ -18,14 +18,14 @@
* *
* These two cases used to be treated identically, but now * These two cases used to be treated identically, but now
* we need to distinguish them. Why? consider the following * we need to distinguish them. Why? consider the following
* two situatuons: * two situations:
* *
* case 1 case 2 * case 1 case 2
* ------ ------ * ------ ------
* 1) user types BEGIN 1) user types BEGIN * 1) user types BEGIN 1) user types BEGIN
* 2) user does something 2) user does something * 2) user does something 2) user does something
* 3) user does not like what 3) system aborts for some reason * 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 * In case 1, we want to abort the transaction and return to the
* default state. In case 2, there may be more commands coming * default state. In case 2, there may be more commands coming
...@@ -42,6 +42,15 @@ ...@@ -42,6 +42,15 @@
* * AbortTransactionBlock() leaves us in TBLOCK_ABORT and * * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
* * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT * * 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 * NOTES
* This file is an attempt at a redesign of the upper layer * This file is an attempt at a redesign of the upper layer
* of the V1 transaction system which was too poorly thought * of the V1 transaction system which was too poorly thought
...@@ -70,7 +79,7 @@ ...@@ -70,7 +79,7 @@
* StartTransaction * StartTransaction
* CommitTransaction * CommitTransaction
* AbortTransaction * AbortTransaction
* UserAbortTransaction * CleanupTransaction
* *
* are provided to do the lower level work like recording * are provided to do the lower level work like recording
* the transaction status in the log and doing memory cleanup. * the transaction status in the log and doing memory cleanup.
...@@ -151,13 +160,15 @@ ...@@ -151,13 +160,15 @@
#include "commands/async.h" #include "commands/async.h"
#include "commands/sequence.h" #include "commands/sequence.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "executor/spi.h"
#include "libpq/be-fsstubs.h" #include "libpq/be-fsstubs.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/sinval.h" #include "storage/sinval.h"
#include "utils/temprel.h"
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/portal.h" #include "utils/portal.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/temprel.h"
extern bool SharedBufferChanged; extern bool SharedBufferChanged;
...@@ -165,6 +176,7 @@ static void AbortTransaction(void); ...@@ -165,6 +176,7 @@ static void AbortTransaction(void);
static void AtAbort_Cache(void); static void AtAbort_Cache(void);
static void AtAbort_Locks(void); static void AtAbort_Locks(void);
static void AtAbort_Memory(void); static void AtAbort_Memory(void);
static void AtCleanup_Memory(void);
static void AtCommit_Cache(void); static void AtCommit_Cache(void);
static void AtCommit_LocalCache(void); static void AtCommit_LocalCache(void);
static void AtCommit_Locks(void); static void AtCommit_Locks(void);
...@@ -172,6 +184,7 @@ static void AtCommit_Memory(void); ...@@ -172,6 +184,7 @@ static void AtCommit_Memory(void);
static void AtStart_Cache(void); static void AtStart_Cache(void);
static void AtStart_Locks(void); static void AtStart_Locks(void);
static void AtStart_Memory(void); static void AtStart_Memory(void);
static void CleanupTransaction(void);
static void CommitTransaction(void); static void CommitTransaction(void);
static void RecordTransactionAbort(void); static void RecordTransactionAbort(void);
static void RecordTransactionCommit(void); static void RecordTransactionCommit(void);
...@@ -243,7 +256,7 @@ bool AMI_OVERRIDE = false; ...@@ -243,7 +256,7 @@ bool AMI_OVERRIDE = false;
/* -------------------------------- /* --------------------------------
* TranactionFlushEnabled() * TranactionFlushEnabled()
* SetTranactionFlushEnabled() * SetTransactionFlushEnabled()
* *
* These are used to test and set the "TransactionFlushState" * These are used to test and set the "TransactionFlushState"
* varable. If this variable is true (the default), then * varable. If this variable is true (the default), then
...@@ -580,22 +593,35 @@ AtStart_Locks() ...@@ -580,22 +593,35 @@ AtStart_Locks()
static void static void
AtStart_Memory() 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); TopTransactionContext =
portalContext = (MemoryContext) PortalGetHeapMemory(portal); 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); TransactionCommandContext =
StartPortalAllocMode(DefaultAllocMode, 0); AllocSetContextCreate(TopTransactionContext,
"TransactionCommandContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
MemoryContextSwitchTo(TransactionCommandContext);
} }
...@@ -711,22 +737,21 @@ AtCommit_Locks() ...@@ -711,22 +737,21 @@ AtCommit_Locks()
static void static void
AtCommit_Memory() 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); MemoryContextSwitchTo(TopMemoryContext);
PortalResetHeapMemory(portal);
/* ---------------- /* ----------------
* Now that we're "out" of a transaction, have the * Release all transaction-local memory.
* system allocate things in the top memory context instead
* of the blank portal memory context.
* ---------------- * ----------------
*/ */
MemoryContextSwitchTo(TopMemoryContext); MemoryContextDelete(TopTransactionContext);
TopTransactionContext = NULL;
TransactionCommandContext = NULL;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -798,24 +823,52 @@ AtAbort_Locks() ...@@ -798,24 +823,52 @@ AtAbort_Locks()
static void static void
AtAbort_Memory() 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); MemoryContextResetAndDeleteChildren(TransactionCommandContext);
PortalResetHeapMemory(portal); }
/* ----------------------------------------------------------------
* CleanupTransaction stuff
* ----------------------------------------------------------------
*/
/* --------------------------------
* AtCleanup_Memory
* --------------------------------
*/
static void
AtCleanup_Memory()
{
/* ---------------- /* ----------------
* Now that we're "out" of a transaction, have the * Now that we're "out" of a transaction, have the
* system allocate things in the top memory context instead * system allocate things in the top memory context instead
* of the blank portal memory context. * of per-transaction contexts.
* ---------------- * ----------------
*/ */
MemoryContextSwitchTo(TopMemoryContext); MemoryContextSwitchTo(TopMemoryContext);
/* ----------------
* Release all transaction-local memory.
* ----------------
*/
MemoryContextDelete(TopTransactionContext);
TopTransactionContext = NULL;
TransactionCommandContext = NULL;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* interface routines * interface routines
* ---------------------------------------------------------------- * ----------------------------------------------------------------
...@@ -854,6 +907,7 @@ StartTransaction() ...@@ -854,6 +907,7 @@ StartTransaction()
s->state = TRANS_START; s->state = TRANS_START;
SetReindexProcessing(false); SetReindexProcessing(false);
/* ---------------- /* ----------------
* generate a new transaction id * generate a new transaction id
* ---------------- * ----------------
...@@ -874,9 +928,9 @@ StartTransaction() ...@@ -874,9 +928,9 @@ StartTransaction()
* initialize the various transaction subsystems * initialize the various transaction subsystems
* ---------------- * ----------------
*/ */
AtStart_Memory();
AtStart_Cache(); AtStart_Cache();
AtStart_Locks(); AtStart_Locks();
AtStart_Memory();
/* ---------------- /* ----------------
* Tell the trigger manager to we're starting a transaction * Tell the trigger manager to we're starting a transaction
...@@ -974,20 +1028,21 @@ CommitTransaction() ...@@ -974,20 +1028,21 @@ CommitTransaction()
} }
RelationPurgeLocalRelation(true); RelationPurgeLocalRelation(true);
AtEOXact_SPI();
AtEOXact_nbtree(); AtEOXact_nbtree();
AtCommit_Cache(); AtCommit_Cache();
AtCommit_Locks(); AtCommit_Locks();
AtCommit_Memory(); AtCommit_Memory();
AtEOXact_Files(); AtEOXact_Files();
SharedBufferChanged = false; /* safest place to do it */
/* ---------------- /* ----------------
* done with commit processing, set current transaction * done with commit processing, set current transaction
* state back to default * state back to default
* ---------------- * ----------------
*/ */
s->state = TRANS_DEFAULT; s->state = TRANS_DEFAULT;
SharedBufferChanged = false;/* safest place to do it */
} }
/* -------------------------------- /* --------------------------------
...@@ -1018,7 +1073,7 @@ AbortTransaction() ...@@ -1018,7 +1073,7 @@ AbortTransaction()
return; return;
if (s->state != TRANS_INPROGRESS) 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 * Tell the trigger manager that this transaction is about to be
...@@ -1043,24 +1098,56 @@ AbortTransaction() ...@@ -1043,24 +1098,56 @@ AbortTransaction()
AtAbort_Notify(); AtAbort_Notify();
CloseSequences(); CloseSequences();
AtEOXact_portals(); AtEOXact_portals();
if (CommonSpecialPortalIsOpen())
CommonSpecialPortalClose();
RecordTransactionAbort(); RecordTransactionAbort();
RelationPurgeLocalRelation(false); RelationPurgeLocalRelation(false);
invalidate_temp_relations(); invalidate_temp_relations();
AtEOXact_SPI();
AtEOXact_nbtree(); AtEOXact_nbtree();
AtAbort_Cache(); AtAbort_Cache();
AtAbort_Locks(); AtAbort_Locks();
AtAbort_Memory(); AtAbort_Memory();
AtEOXact_Files(); 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 * done with abort processing, set current transaction
* state back to default * state back to default
* ---------------- * ----------------
*/ */
s->state = TRANS_DEFAULT; s->state = TRANS_DEFAULT;
SharedBufferChanged = false;/* safest place to do it */
} }
/* -------------------------------- /* --------------------------------
...@@ -1133,7 +1220,7 @@ StartTransactionCommand() ...@@ -1133,7 +1220,7 @@ StartTransactionCommand()
/* ---------------- /* ----------------
* This means we somehow aborted and the last call to * This means we somehow aborted and the last call to
* CommitTransactionCommand() didn't clear the state so * 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 * we get to CommitTransactionCommand() the state will
* get reset to default. * get reset to default.
* ---------------- * ----------------
...@@ -1142,6 +1229,13 @@ StartTransactionCommand() ...@@ -1142,6 +1229,13 @@ StartTransactionCommand()
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT"); elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
break; 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() ...@@ -1181,28 +1275,25 @@ CommitTransactionCommand()
* command counter and return. Someday we may free resources * command counter and return. Someday we may free resources
* local to the command. * local to the command.
* *
* That someday is today, at least for memory allocated by * That someday is today, at least for memory allocated in
* command in the BlankPortal' HeapMemory context. * TransactionCommandContext.
* - vadim 03/25/97 * - vadim 03/25/97
* ---------------- * ----------------
*/ */
case TBLOCK_INPROGRESS: case TBLOCK_INPROGRESS:
CommandCounterIncrement(); CommandCounterIncrement();
#ifdef TBL_FREE_CMD_MEMORY MemoryContextResetAndDeleteChildren(TransactionCommandContext);
EndPortalAllocMode();
StartPortalAllocMode(DefaultAllocMode, 0);
#endif
break; break;
/* ---------------- /* ----------------
* This is the case when we just got the "END TRANSACTION" * This is the case when we just got the "END TRANSACTION"
* statement, so we go back to the default state and * statement, so we commit the transaction and go back to
* commit the transaction. * the default state.
* ---------------- * ----------------
*/ */
case TBLOCK_END: case TBLOCK_END:
s->blockState = TBLOCK_DEFAULT;
CommitTransaction(); CommitTransaction();
s->blockState = TBLOCK_DEFAULT;
break; break;
/* ---------------- /* ----------------
...@@ -1218,10 +1309,11 @@ CommitTransactionCommand() ...@@ -1218,10 +1309,11 @@ CommitTransactionCommand()
/* ---------------- /* ----------------
* Here we were in an aborted transaction block which * Here we were in an aborted transaction block which
* just processed the "END TRANSACTION" command from the * 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: case TBLOCK_ENDABORT:
CleanupTransaction();
s->blockState = TBLOCK_DEFAULT; s->blockState = TBLOCK_DEFAULT;
break; break;
} }
...@@ -1240,11 +1332,12 @@ AbortCurrentTransaction() ...@@ -1240,11 +1332,12 @@ AbortCurrentTransaction()
{ {
/* ---------------- /* ----------------
* if we aren't in a transaction block, we * 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: case TBLOCK_DEFAULT:
AbortTransaction(); AbortTransaction();
CleanupTransaction();
break; break;
/* ---------------- /* ----------------
...@@ -1257,6 +1350,7 @@ AbortCurrentTransaction() ...@@ -1257,6 +1350,7 @@ AbortCurrentTransaction()
case TBLOCK_BEGIN: case TBLOCK_BEGIN:
s->blockState = TBLOCK_ABORT; s->blockState = TBLOCK_ABORT;
AbortTransaction(); AbortTransaction();
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
break; break;
/* ---------------- /* ----------------
...@@ -1269,6 +1363,7 @@ AbortCurrentTransaction() ...@@ -1269,6 +1363,7 @@ AbortCurrentTransaction()
case TBLOCK_INPROGRESS: case TBLOCK_INPROGRESS:
s->blockState = TBLOCK_ABORT; s->blockState = TBLOCK_ABORT;
AbortTransaction(); AbortTransaction();
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
break; break;
/* ---------------- /* ----------------
...@@ -1281,6 +1376,7 @@ AbortCurrentTransaction() ...@@ -1281,6 +1376,7 @@ AbortCurrentTransaction()
case TBLOCK_END: case TBLOCK_END:
s->blockState = TBLOCK_DEFAULT; s->blockState = TBLOCK_DEFAULT;
AbortTransaction(); AbortTransaction();
CleanupTransaction();
break; break;
/* ---------------- /* ----------------
...@@ -1297,10 +1393,11 @@ AbortCurrentTransaction() ...@@ -1297,10 +1393,11 @@ AbortCurrentTransaction()
* Here we were in an aborted transaction block which * Here we were in an aborted transaction block which
* just processed the "END TRANSACTION" command but somehow * just processed the "END TRANSACTION" command but somehow
* aborted again.. since we must have done the abort * 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: case TBLOCK_ENDABORT:
CleanupTransaction();
s->blockState = TBLOCK_DEFAULT; s->blockState = TBLOCK_DEFAULT;
break; break;
} }
...@@ -1394,13 +1491,14 @@ EndTransactionBlock(void) ...@@ -1394,13 +1491,14 @@ EndTransactionBlock(void)
} }
/* ---------------- /* ----------------
* We should not get here, but if we do, we go to the ENDABORT * here, the user issued COMMIT when not inside a transaction.
* state after printing a warning. The upcoming call to * Issue a notice and go to abort state. The upcoming call to
* CommitTransactionCommand() will then put us back into the * CommitTransactionCommand() will then put us back into the
* default state. * default state.
* ---------------- * ----------------
*/ */
elog(NOTICE, "COMMIT: no transaction in progress"); elog(NOTICE, "COMMIT: no transaction in progress");
AbortTransaction();
s->blockState = TBLOCK_ENDABORT; s->blockState = TBLOCK_ENDABORT;
} }
...@@ -1427,29 +1525,23 @@ AbortTransactionBlock(void) ...@@ -1427,29 +1525,23 @@ AbortTransactionBlock(void)
* here we were inside a transaction block something * here we were inside a transaction block something
* screwed up inside the system so we enter the abort state, * screwed up inside the system so we enter the abort state,
* do the abort processing and then return. * 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. * END TRANSACTION command.
* ---------------- * ----------------
*/ */
s->blockState = TBLOCK_ABORT; s->blockState = TBLOCK_ABORT;
/* ----------------
* do abort processing and return
* ----------------
*/
AbortTransaction(); AbortTransaction();
return; return;
} }
/* ---------------- /* ----------------
* this case should not be possible, because it would mean * here, the user issued ABORT when not inside a transaction.
* the user entered an "abort" from outside a transaction block. * Issue a notice and go to abort state. The upcoming call to
* So we print an error message, abort the transaction and * CommitTransactionCommand() will then put us back into the
* enter the "ENDABORT" state so we will end up in the default * default state.
* state after the upcoming CommitTransactionCommand().
* ---------------- * ----------------
*/ */
elog(NOTICE, "AbortTransactionBlock and not in in-progress state"); elog(NOTICE, "ROLLBACK: no transaction in progress");
AbortTransaction(); AbortTransaction();
s->blockState = TBLOCK_ENDABORT; s->blockState = TBLOCK_ENDABORT;
} }
...@@ -1495,27 +1587,16 @@ UserAbortTransactionBlock() ...@@ -1495,27 +1587,16 @@ UserAbortTransactionBlock()
* ---------------- * ----------------
*/ */
s->blockState = TBLOCK_ABORT; s->blockState = TBLOCK_ABORT;
/* ----------------
* do abort processing
* ----------------
*/
AbortTransaction(); AbortTransaction();
/* ----------------
* change to the end abort state and return
* ----------------
*/
s->blockState = TBLOCK_ENDABORT; s->blockState = TBLOCK_ENDABORT;
return; return;
} }
/* ---------------- /* ----------------
* this case should not be possible, because it would mean * here, the user issued ABORT when not inside a transaction.
* the user entered a "rollback" from outside a transaction block. * Issue a notice and go to abort state. The upcoming call to
* So we print an error message, abort the transaction and * CommitTransactionCommand() will then put us back into the
* enter the "ENDABORT" state so we will end up in the default * default state.
* state after the upcoming CommitTransactionCommand().
* ---------------- * ----------------
*/ */
elog(NOTICE, "ROLLBACK: no transaction in progress"); elog(NOTICE, "ROLLBACK: no transaction in progress");
...@@ -1540,7 +1621,10 @@ AbortOutOfAnyTransaction() ...@@ -1540,7 +1621,10 @@ AbortOutOfAnyTransaction()
* Get out of any low-level transaction * Get out of any low-level transaction
*/ */
if (s->state != TRANS_DEFAULT) if (s->state != TRANS_DEFAULT)
{
AbortTransaction(); AbortTransaction();
CleanupTransaction();
}
/* /*
* Now reset the high-level state * Now reset the high-level state
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -34,14 +34,14 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/exc.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/portal.h"
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t))) #define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
extern void BaseInit(void);
extern void StartupXLOG(void); extern void StartupXLOG(void);
extern void ShutdownXLOG(void); extern void ShutdownXLOG(void);
extern void BootStrapXLOG(void); extern void BootStrapXLOG(void);
...@@ -144,8 +144,8 @@ static Datum values[MAXATTR]; /* corresponding attribute values */ ...@@ -144,8 +144,8 @@ static Datum values[MAXATTR]; /* corresponding attribute values */
int numattr; /* number of attributes for cur. rel */ int numattr; /* number of attributes for cur. rel */
int DebugMode; 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 int optind;
extern char *optarg; extern char *optarg;
...@@ -240,6 +240,17 @@ BootstrapMain(int argc, char *argv[]) ...@@ -240,6 +240,17 @@ BootstrapMain(int argc, char *argv[])
MyProcPid = getpid(); 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 * process command arguments
* ---------------- * ----------------
...@@ -428,7 +439,6 @@ boot_openrel(char *relname) ...@@ -428,7 +439,6 @@ boot_openrel(char *relname)
if (Typ == (struct typmap **) NULL) if (Typ == (struct typmap **) NULL)
{ {
StartPortalAllocMode(DefaultAllocMode, 0);
rel = heap_openr(TypeRelationName, NoLock); rel = heap_openr(TypeRelationName, NoLock);
Assert(rel); Assert(rel);
scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL); scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
...@@ -445,13 +455,13 @@ boot_openrel(char *relname) ...@@ -445,13 +455,13 @@ boot_openrel(char *relname)
while (HeapTupleIsValid(tup = heap_getnext(scan, 0))) while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
{ {
(*app)->am_oid = tup->t_data->t_oid; (*app)->am_oid = tup->t_data->t_oid;
memmove((char *) &(*app++)->am_typ, memcpy((char *) &(*app)->am_typ,
(char *) GETSTRUCT(tup), (char *) GETSTRUCT(tup),
sizeof((*app)->am_typ)); sizeof((*app)->am_typ));
app++;
} }
heap_endscan(scan); heap_endscan(scan);
heap_close(rel, NoLock); heap_close(rel, NoLock);
EndPortalAllocMode();
} }
if (reldesc != NULL) if (reldesc != NULL)
...@@ -1088,10 +1098,14 @@ index_register(char *heap, ...@@ -1088,10 +1098,14 @@ index_register(char *heap,
* them later. * them later.
*/ */
if (nogc == (GlobalMemory) NULL) if (nogc == NULL)
nogc = CreateGlobalMemory("BootstrapNoGC"); 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 = (IndexList *) palloc(sizeof(IndexList));
newind->il_heap = pstrdup(heap); newind->il_heap = pstrdup(heap);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -188,38 +188,27 @@ heap_create(char *relname, ...@@ -188,38 +188,27 @@ heap_create(char *relname,
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 * real ugly stuff to assign the proper relid in the relation
* descriptor follows. * descriptor follows.
* ---------------- * ----------------
*/ */
if (relname && !strcmp(RelationRelationName, relname)) if (relname && strcmp(RelationRelationName, relname) == 0)
{ {
relid = RelOid_pg_class; relid = RelOid_pg_class;
nailme = true; nailme = true;
} }
else if (relname && !strcmp(AttributeRelationName, relname)) else if (relname && strcmp(AttributeRelationName, relname) == 0)
{ {
relid = RelOid_pg_attribute; relid = RelOid_pg_attribute;
nailme = true; nailme = true;
} }
else if (relname && !strcmp(ProcedureRelationName, relname)) else if (relname && strcmp(ProcedureRelationName, relname) == 0)
{ {
relid = RelOid_pg_proc; relid = RelOid_pg_proc;
nailme = true; nailme = true;
} }
else if (relname && !strcmp(TypeRelationName, relname)) else if (relname && strcmp(TypeRelationName, relname) == 0)
{ {
relid = RelOid_pg_type; relid = RelOid_pg_type;
nailme = true; nailme = true;
...@@ -234,6 +223,15 @@ heap_create(char *relname, ...@@ -234,6 +223,15 @@ heap_create(char *relname,
(int) MyProcPid, uniqueId++); (int) MyProcPid, uniqueId++);
} }
/* ----------------
* switch to the cache context to create the relcache entry.
* ----------------
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* allocate a new relation descriptor. * allocate a new relation descriptor.
* ---------------- * ----------------
...@@ -287,6 +285,8 @@ heap_create(char *relname, ...@@ -287,6 +285,8 @@ heap_create(char *relname,
/* ---------------- /* ----------------
* have the storage manager create the relation. * have the storage manager create the relation.
*
* XXX shouldn't we switch out of CacheMemoryContext for that?
* ---------------- * ----------------
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -442,10 +442,10 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid) ...@@ -442,10 +442,10 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
* context changes * context changes
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid); indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
...@@ -904,16 +904,16 @@ InitIndexStrategy(int numatts, ...@@ -904,16 +904,16 @@ InitIndexStrategy(int numatts,
* it will be lost at the end of the transaction. * it will be lost at the end of the transaction.
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
strategy = (IndexStrategy) strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
MemoryContextAlloc((MemoryContext) CacheCxt, strsize); strsize);
if (amsupport > 0) if (amsupport > 0)
{ {
strsize = numatts * (amsupport * sizeof(RegProcedure)); strsize = numatts * (amsupport * sizeof(RegProcedure));
support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt, support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
strsize); strsize);
} }
else else
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -217,8 +217,7 @@ ProcedureCreate(char *procedureName,
if (languageObjectId == SQLlanguageId) if (languageObjectId == SQLlanguageId)
{ {
querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount, querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount);
FALSE);
/* typecheck return value */ /* typecheck return value */
pg_checkretval(typeObjectId, querytree_list); pg_checkretval(typeObjectId, querytree_list);
} }
......
...@@ -8,13 +8,9 @@ ...@@ -8,13 +8,9 @@
* *
* *
* IDENTIFICATION * 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 * 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 * The PerformAddAttribute() code, like most of the relation
* manipulating code in the commands/ directory, should go * manipulating code in the commands/ directory, should go
* someplace closer to the lib/catalog code. * someplace closer to the lib/catalog code.
...@@ -40,13 +36,6 @@ ...@@ -40,13 +36,6 @@
#include "parser/parse.h" #include "parser/parse.h"
#endif /* _DROP_COLUMN_HACK__ */ #endif /* _DROP_COLUMN_HACK__ */
/* ----------------
* PortalExecutorHeapMemory stuff
*
* This is where the XXXSuperDuperHacky code was. -cim 3/15/90
* ----------------
*/
MemoryContext PortalExecutorHeapMemory = NULL;
/* -------------------------------- /* --------------------------------
* PortalCleanup * PortalCleanup
...@@ -55,7 +44,7 @@ MemoryContext PortalExecutorHeapMemory = NULL; ...@@ -55,7 +44,7 @@ MemoryContext PortalExecutorHeapMemory = NULL;
void void
PortalCleanup(Portal portal) PortalCleanup(Portal portal)
{ {
MemoryContext context; MemoryContext oldcontext;
/* ---------------- /* ----------------
* sanity checks * sanity checks
...@@ -68,8 +57,7 @@ PortalCleanup(Portal portal) ...@@ -68,8 +57,7 @@ PortalCleanup(Portal portal)
* set proper portal-executor context before calling ExecMain. * set proper portal-executor context before calling ExecMain.
* ---------------- * ----------------
*/ */
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal)); oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
/* ---------------- /* ----------------
* tell the executor to shutdown the query * tell the executor to shutdown the query
...@@ -81,8 +69,7 @@ PortalCleanup(Portal portal) ...@@ -81,8 +69,7 @@ PortalCleanup(Portal portal)
* switch back to previous context * switch back to previous context
* ---------------- * ----------------
*/ */
MemoryContextSwitchTo(context); MemoryContextSwitchTo(oldcontext);
PortalExecutorHeapMemory = (MemoryContext) NULL;
} }
/* -------------------------------- /* --------------------------------
...@@ -99,7 +86,7 @@ PerformPortalFetch(char *name, ...@@ -99,7 +86,7 @@ PerformPortalFetch(char *name,
Portal portal; Portal portal;
int feature; int feature;
QueryDesc *queryDesc; QueryDesc *queryDesc;
MemoryContext context; MemoryContext oldcontext;
Const limcount; Const limcount;
/* ---------------- /* ----------------
...@@ -108,7 +95,7 @@ PerformPortalFetch(char *name, ...@@ -108,7 +95,7 @@ PerformPortalFetch(char *name,
*/ */
if (name == NULL) if (name == NULL)
{ {
elog(NOTICE, "PerformPortalFetch: blank portal unsupported"); elog(NOTICE, "PerformPortalFetch: missing portal name");
return; return;
} }
...@@ -120,12 +107,11 @@ PerformPortalFetch(char *name, ...@@ -120,12 +107,11 @@ PerformPortalFetch(char *name,
limcount.type = T_Const; limcount.type = T_Const;
limcount.consttype = INT4OID; limcount.consttype = INT4OID;
limcount.constlen = sizeof(int4); limcount.constlen = sizeof(int4);
limcount.constvalue = (Datum) count; limcount.constvalue = Int32GetDatum(count);
limcount.constisnull = FALSE; limcount.constisnull = false;
limcount.constbyval = TRUE; limcount.constbyval = true;
limcount.constisset = FALSE; limcount.constisset = false;
limcount.constiscast = FALSE; limcount.constiscast = false;
/* ---------------- /* ----------------
* get the portal from the portal name * get the portal from the portal name
...@@ -143,9 +129,7 @@ PerformPortalFetch(char *name, ...@@ -143,9 +129,7 @@ PerformPortalFetch(char *name,
* switch into the portal context * switch into the portal context
* ---------------- * ----------------
*/ */
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal)); oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
/* ---------------- /* ----------------
* setup "feature" to tell the executor what direction and * setup "feature" to tell the executor what direction and
...@@ -174,8 +158,7 @@ PerformPortalFetch(char *name, ...@@ -174,8 +158,7 @@ PerformPortalFetch(char *name,
BeginCommand(name, BeginCommand(name,
queryDesc->operation, queryDesc->operation,
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc), portal->attinfo, /* QueryDescGetTypeInfo(queryDesc) */
* */
false, /* portal fetches don't end up in false, /* portal fetches don't end up in
* relations */ * relations */
false, /* this is a portal fetch, not a "retrieve false, /* this is a portal fetch, not a "retrieve
...@@ -187,27 +170,23 @@ PerformPortalFetch(char *name, ...@@ -187,27 +170,23 @@ PerformPortalFetch(char *name,
* execute the portal fetch operation * execute the portal fetch operation
* ---------------- * ----------------
*/ */
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
ExecutorRun(queryDesc, PortalGetState(portal), feature, ExecutorRun(queryDesc, PortalGetState(portal), feature,
(Node *) NULL, (Node *) &limcount); (Node *) NULL, (Node *) &limcount);
if (dest == None) /* MOVE */ if (dest == None) /* MOVE */
pfree(queryDesc); pfree(queryDesc);
/* ----------------
* Switch back to old context.
* ----------------
*/
MemoryContextSwitchTo(oldcontext);
/* ---------------- /* ----------------
* Note: the "end-of-command" tag is returned by higher-level * Note: the "end-of-command" tag is returned by higher-level
* utility code * 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) ...@@ -225,15 +204,10 @@ PerformPortalClose(char *name, CommandDest dest)
*/ */
if (name == NULL) if (name == NULL)
{ {
elog(NOTICE, "PerformPortalClose: blank portal unsupported"); elog(NOTICE, "PerformPortalClose: missing portal name");
return; return;
} }
if (PortalNameIsSpecial(name))
elog(ERROR,
"The portal name \"%s\" is reserved for internal use",
name);
/* ---------------- /* ----------------
* get the portal from the portal name * get the portal from the portal name
* ---------------- * ----------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -39,7 +39,6 @@
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "miscadmin.h" /* ReindexDatabase() */ #include "miscadmin.h" /* ReindexDatabase() */
#include "utils/portal.h" /* ReindexDatabase() */
#include "catalog/catalog.h" /* ReindexDatabase() */ #include "catalog/catalog.h" /* ReindexDatabase() */
#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL) #define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
...@@ -764,7 +763,6 @@ ReindexTable(const char *name, bool force) ...@@ -764,7 +763,6 @@ ReindexTable(const char *name, bool force)
* "ERROR" if table nonexistent. * "ERROR" if table nonexistent.
* ... * ...
*/ */
extern Oid MyDatabaseId;
void void
ReindexDatabase(const char *dbname, bool force, bool all) ReindexDatabase(const char *dbname, bool force, bool all)
{ {
...@@ -780,7 +778,7 @@ ReindexDatabase(const char *dbname, bool force, bool all) ...@@ -780,7 +778,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
Oid db_id; Oid db_id;
char *username; char *username;
ScanKeyData scankey; ScanKeyData scankey;
PortalVariableMemory pmem; MemoryContext private_context;
MemoryContext old; MemoryContext old;
int relcnt, int relcnt,
relalc, relalc,
...@@ -808,16 +806,34 @@ ReindexDatabase(const char *dbname, bool force, bool all) ...@@ -808,16 +806,34 @@ ReindexDatabase(const char *dbname, bool force, bool all)
db_id = dbtuple->t_data->t_oid; db_id = dbtuple->t_data->t_oid;
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba; db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
heap_endscan(scan); heap_endscan(scan);
heap_close(relation, NoLock);
if (user_id != db_owner && !superuser) if (user_id != db_owner && !superuser)
elog(ERROR, "REINDEX DATABASE: Permission denied."); elog(ERROR, "REINDEX DATABASE: Permission denied.");
if (db_id != MyDatabaseId) if (db_id != MyDatabaseId)
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database."); 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); relationRelation = heap_openr(RelationRelationName, AccessShareLock);
scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL); scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL);
relcnt = relalc = 0; relcnt = relalc = 0;
...@@ -832,7 +848,7 @@ ReindexDatabase(const char *dbname, bool force, bool all) ...@@ -832,7 +848,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
} }
if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION) if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
{ {
old = MemoryContextSwitchTo((MemoryContext) pmem); old = MemoryContextSwitchTo(private_context);
if (relcnt == 0) if (relcnt == 0)
{ {
relalc = oncealc; relalc = oncealc;
...@@ -859,6 +875,7 @@ ReindexDatabase(const char *dbname, bool force, bool all) ...@@ -859,6 +875,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
elog(NOTICE, "relation %d was reindexed", relids[i]); elog(NOTICE, "relation %d was reindexed", relids[i]);
CommitTransactionCommand(); CommitTransactionCommand();
} }
CommonSpecialPortalClose();
StartTransactionCommand(); StartTransactionCommand();
MemoryContextDelete(private_context);
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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:; ...@@ -1029,8 +1029,8 @@ ltrmark:;
* end. * end.
* ---------- * ----------
*/ */
static GlobalMemory deftrig_gcxt = NULL; static MemoryContext deftrig_gcxt = NULL;
static GlobalMemory deftrig_cxt = NULL; static MemoryContext deftrig_cxt = NULL;
/* ---------- /* ----------
* Global data that tells which triggers are actually in * Global data that tells which triggers are actually in
...@@ -1104,7 +1104,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate) ...@@ -1104,7 +1104,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
* as the current and return that. * as the current and return that.
* ---------- * ----------
*/ */
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt); oldcxt = MemoryContextSwitchTo(deftrig_cxt);
trigstate = (DeferredTriggerStatus) trigstate = (DeferredTriggerStatus)
palloc(sizeof(DeferredTriggerStatusData)); palloc(sizeof(DeferredTriggerStatusData));
...@@ -1366,7 +1366,12 @@ deferredTriggerInvokeEvents(bool immediate_only) ...@@ -1366,7 +1366,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
int int
DeferredTriggerInit(void) DeferredTriggerInit(void)
{ {
deftrig_gcxt = CreateGlobalMemory("DeferredTriggerSession"); deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
"DeferredTriggerSession",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
return 0; return 0;
} }
...@@ -1395,8 +1400,12 @@ DeferredTriggerBeginXact(void) ...@@ -1395,8 +1400,12 @@ DeferredTriggerBeginXact(void)
* from the per session context to here. * from the per session context to here.
* ---------- * ----------
*/ */
deftrig_cxt = CreateGlobalMemory("DeferredTriggerXact"); deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt); "DeferredTriggerXact",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
deftrig_all_isset = deftrig_dfl_all_isset; deftrig_all_isset = deftrig_dfl_all_isset;
deftrig_all_isdeferred = deftrig_dfl_all_isdeferred; deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
...@@ -1461,7 +1470,7 @@ DeferredTriggerEndXact(void) ...@@ -1461,7 +1470,7 @@ DeferredTriggerEndXact(void)
deferredTriggerInvokeEvents(false); deferredTriggerInvokeEvents(false);
GlobalMemoryDestroy(deftrig_cxt); MemoryContextDelete(deftrig_cxt);
deftrig_cxt = NULL; deftrig_cxt = NULL;
} }
...@@ -1484,7 +1493,7 @@ DeferredTriggerAbortXact(void) ...@@ -1484,7 +1493,7 @@ DeferredTriggerAbortXact(void)
if (deftrig_cxt == NULL) if (deftrig_cxt == NULL)
return; return;
GlobalMemoryDestroy(deftrig_cxt); MemoryContextDelete(deftrig_cxt);
deftrig_cxt = NULL; deftrig_cxt = NULL;
} }
...@@ -1521,7 +1530,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) ...@@ -1521,7 +1530,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ... outside of a transaction block * ... outside of a transaction block
* ---------- * ----------
*/ */
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt); oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
/* ---------- /* ----------
* Drop all information about individual trigger states per * Drop all information about individual trigger states per
...@@ -1555,7 +1564,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) ...@@ -1555,7 +1564,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ... inside of a transaction block * ... inside of a transaction block
* ---------- * ----------
*/ */
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt); oldcxt = MemoryContextSwitchTo(deftrig_cxt);
/* ---------- /* ----------
* Drop all information about individual trigger states per * Drop all information about individual trigger states per
...@@ -1701,7 +1710,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) ...@@ -1701,7 +1710,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* states of individual triggers on session level. * states of individual triggers on session level.
* ---------- * ----------
*/ */
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt); oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
foreach(l, loid) foreach(l, loid)
{ {
...@@ -1739,7 +1748,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt) ...@@ -1739,7 +1748,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* states of individual triggers on transaction level. * states of individual triggers on transaction level.
* ---------- * ----------
*/ */
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt); oldcxt = MemoryContextSwitchTo(deftrig_cxt);
foreach(l, loid) foreach(l, loid)
{ {
...@@ -1827,7 +1836,7 @@ DeferredTriggerSaveEvent(Relation rel, int event, ...@@ -1827,7 +1836,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
* Create a new event * Create a new event
* ---------- * ----------
*/ */
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt); oldcxt = MemoryContextSwitchTo(deftrig_cxt);
ntriggers = rel->trigdesc->n_after_row[event]; ntriggers = rel->trigdesc->n_after_row[event];
triggers = rel->trigdesc->tg_after_row[event]; triggers = rel->trigdesc->tg_after_row[event];
...@@ -2022,7 +2031,7 @@ DeferredTriggerSaveEvent(Relation rel, int event, ...@@ -2022,7 +2031,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
* Anything's fine up to here. Add the new event to the queue. * 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); deferredTriggerAddEvent(new_event);
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* user.c * 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) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -35,7 +35,6 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/portal.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/temprel.h" #include "utils/temprel.h"
...@@ -48,9 +47,7 @@ ...@@ -48,9 +47,7 @@
#endif #endif
bool CommonSpecialPortalInUse = false; static MemoryContext vac_context = NULL;
static Portal vac_portal;
static int MESSAGE_LEVEL; /* message level */ static int MESSAGE_LEVEL; /* message level */
...@@ -82,14 +79,13 @@ static int vac_cmp_offno(const void *left, const void *right); ...@@ -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 int vac_cmp_vtlinks(const void *left, const void *right);
static bool enough_space(VacPage vacpage, Size len); static bool enough_space(VacPage vacpage, Size len);
static char *show_rusage(struct rusage * ru0); static char *show_rusage(struct rusage * ru0);
/* CommonSpecialPortal function at the bottom */
void void
vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols) vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
{ {
NameData VacRel; NameData VacRel;
Name VacRelName; Name VacRelName;
PortalVariableMemory pmem;
MemoryContext old; MemoryContext old;
List *le; List *le;
List *anal_cols2 = NIL; List *anal_cols2 = NIL;
...@@ -114,8 +110,18 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols) ...@@ -114,8 +110,18 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
else else
MESSAGE_LEVEL = DEBUG; 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 */ /* vacrel gets de-allocated on xact commit, so copy it to safe storage */
if (vacrel) if (vacrel)
...@@ -127,8 +133,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols) ...@@ -127,8 +133,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
VacRelName = NULL; VacRelName = NULL;
/* must also copy the column list, if any, to safe storage */ /* must also copy the column list, if any, to safe storage */
pmem = CommonSpecialPortalGetMemory(); old = MemoryContextSwitchTo(vac_context);
old = MemoryContextSwitchTo((MemoryContext) pmem);
foreach(le, anal_cols) foreach(le, anal_cols)
{ {
char *col = (char *) lfirst(le); char *col = (char *) lfirst(le);
...@@ -198,11 +203,16 @@ vacuum_shutdown() ...@@ -198,11 +203,16 @@ vacuum_shutdown()
*/ */
unlink(RELCACHE_INIT_FILENAME); unlink(RELCACHE_INIT_FILENAME);
/* Clean up working storage */
CommonSpecialPortalClose();
/* matches the CommitTransaction in PostgresMain() */ /* matches the CommitTransaction in PostgresMain() */
StartTransactionCommand(); 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) ...@@ -239,8 +249,6 @@ getrels(NameData *VacRelP)
TupleDesc tupdesc; TupleDesc tupdesc;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
PortalVariableMemory portalmem;
MemoryContext old;
VRelList vrl, VRelList vrl,
cur; cur;
Datum d; Datum d;
...@@ -276,7 +284,6 @@ getrels(NameData *VacRelP) ...@@ -276,7 +284,6 @@ getrels(NameData *VacRelP)
F_CHAREQ, CharGetDatum('r')); F_CHAREQ, CharGetDatum('r'));
} }
portalmem = CommonSpecialPortalGetMemory();
vrl = cur = (VRelList) NULL; vrl = cur = (VRelList) NULL;
rel = heap_openr(RelationRelationName, AccessShareLock); rel = heap_openr(RelationRelationName, AccessShareLock);
...@@ -302,25 +309,26 @@ getrels(NameData *VacRelP) ...@@ -302,25 +309,26 @@ getrels(NameData *VacRelP)
} }
/* get a relation list entry for this guy */ /* get a relation list entry for this guy */
old = MemoryContextSwitchTo((MemoryContext) portalmem);
if (vrl == (VRelList) NULL) if (vrl == (VRelList) NULL)
vrl = cur = (VRelList) palloc(sizeof(VRelListData)); vrl = cur = (VRelList)
MemoryContextAlloc(vac_context, sizeof(VRelListData));
else else
{ {
cur->vrl_next = (VRelList) palloc(sizeof(VRelListData)); cur->vrl_next = (VRelList)
MemoryContextAlloc(vac_context, sizeof(VRelListData));
cur = cur->vrl_next; cur = cur->vrl_next;
} }
MemoryContextSwitchTo(old);
cur->vrl_relid = tuple->t_data->t_oid; cur->vrl_relid = tuple->t_data->t_oid;
cur->vrl_next = (VRelList) NULL; cur->vrl_next = (VRelList) NULL;
} }
if (found == false)
elog(NOTICE, "Vacuum: table not found");
heap_endscan(scan); heap_endscan(scan);
heap_close(rel, AccessShareLock); heap_close(rel, AccessShareLock);
if (!found)
elog(NOTICE, "Vacuum: table not found");
CommitTransactionCommand(); CommitTransactionCommand();
return vrl; return vrl;
...@@ -2275,62 +2283,6 @@ vac_cmp_vtlinks(const void *left, const void *right) ...@@ -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 static void
get_indices(Relation relation, int *nindices, Relation **Irel) get_indices(Relation relation, int *nindices, Relation **Irel)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -87,8 +87,8 @@ init_execution_state(FunctionCachePtr fcache)
nextes = newes; nextes = newes;
preves = (execution_state *) NULL; preves = (execution_state *) NULL;
queryTree_list = pg_parse_and_rewrite(fcache->src, fcache->argOidVect, queryTree_list = pg_parse_and_rewrite(fcache->src,
nargs, FALSE); fcache->argOidVect, nargs);
foreach(qtl_item, queryTree_list) foreach(qtl_item, queryTree_list)
{ {
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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, ...@@ -265,7 +265,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
else else
newVal = FunctionCallInvoke(&fcinfo); newVal = FunctionCallInvoke(&fcinfo);
if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull) if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
pfree(peraggstate->value1); pfree(DatumGetPointer(peraggstate->value1));
peraggstate->value1 = newVal; peraggstate->value1 = newVal;
peraggstate->value1IsNull = fcinfo.isnull; peraggstate->value1IsNull = fcinfo.isnull;
} }
...@@ -288,7 +288,7 @@ advance_transition_functions(AggStatePerAgg peraggstate, ...@@ -288,7 +288,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
else else
newVal = FunctionCallInvoke(&fcinfo); newVal = FunctionCallInvoke(&fcinfo);
if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull) if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
pfree(peraggstate->value2); pfree(DatumGetPointer(peraggstate->value2));
peraggstate->value2 = newVal; peraggstate->value2 = newVal;
peraggstate->value2IsNull = fcinfo.isnull; peraggstate->value2IsNull = fcinfo.isnull;
} }
...@@ -424,12 +424,12 @@ finalize_aggregate(AggStatePerAgg peraggstate, ...@@ -424,12 +424,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
if (OidIsValid(peraggstate->xfn1_oid) && if (OidIsValid(peraggstate->xfn1_oid) &&
!peraggstate->value1IsNull && !peraggstate->value1IsNull &&
!peraggstate->transtype1ByVal) !peraggstate->transtype1ByVal)
pfree(peraggstate->value1); pfree(DatumGetPointer(peraggstate->value1));
if (OidIsValid(peraggstate->xfn2_oid) && if (OidIsValid(peraggstate->xfn2_oid) &&
!peraggstate->value2IsNull && !peraggstate->value2IsNull &&
!peraggstate->transtype2ByVal) !peraggstate->transtype2ByVal)
pfree(peraggstate->value2); pfree(DatumGetPointer(peraggstate->value2));
} }
/* --------------------------------------- /* ---------------------------------------
......
...@@ -7,14 +7,14 @@ ...@@ -7,14 +7,14 @@
* Portions Copyright (c) 1994, Regents of the University of California * 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 * INTERFACE ROUTINES
* ExecHash - generate an in-memory hash table of the relation * 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 * ExecEndHash - shutdown node and subnodes
* *
*/ */
...@@ -23,11 +23,12 @@ ...@@ -23,11 +23,12 @@
#include <math.h> #include <math.h>
#include "postgres.h" #include "postgres.h"
#include "executor/execdebug.h" #include "executor/execdebug.h"
#include "executor/nodeHash.h" #include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h" #include "executor/nodeHashjoin.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/portal.h"
static int hashFunc(Datum key, int len, bool byVal); static int hashFunc(Datum key, int len, bool byVal);
...@@ -235,8 +236,6 @@ ExecHashTableCreate(Hash *node) ...@@ -235,8 +236,6 @@ ExecHashTableCreate(Hash *node)
int totalbuckets; int totalbuckets;
int bucketsize; int bucketsize;
int i; int i;
Portal myPortal;
char myPortalName[64];
MemoryContext oldcxt; MemoryContext oldcxt;
/* ---------------- /* ----------------
...@@ -348,23 +347,21 @@ ExecHashTableCreate(Hash *node) ...@@ -348,23 +347,21 @@ ExecHashTableCreate(Hash *node)
hashtable->outerBatchSize = NULL; hashtable->outerBatchSize = NULL;
/* ---------------- /* ----------------
* Create a named portal in which to keep the hashtable working storage. * Create temporary memory contexts in which to keep the hashtable
* Each hashjoin must have its own portal, so be wary of name conflicts. * working storage. See notes in executor/hashjoin.h.
* ---------------- * ----------------
*/ */
i = 0; hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
do "HashTableContext",
{ ALLOCSET_DEFAULT_MINSIZE,
i++; ALLOCSET_DEFAULT_INITSIZE,
sprintf(myPortalName, "<hashtable %d>", i); ALLOCSET_DEFAULT_MAXSIZE);
myPortal = GetPortalByName(myPortalName);
} while (PortalIsValid(myPortal)); hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
myPortal = CreatePortal(myPortalName); "HashBatchContext",
Assert(PortalIsValid(myPortal)); ALLOCSET_DEFAULT_MINSIZE,
hashtable->myPortal = (void *) myPortal; /* kluge for circular ALLOCSET_DEFAULT_INITSIZE,
* includes */ ALLOCSET_DEFAULT_MAXSIZE);
hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
/* Allocate data that will live for the life of the hashjoin */ /* Allocate data that will live for the life of the hashjoin */
...@@ -395,11 +392,10 @@ ExecHashTableCreate(Hash *node) ...@@ -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". * hashbucket array therein, and set each bucket "empty".
*/ */
MemoryContextSwitchTo(hashtable->batchCxt); MemoryContextSwitchTo(hashtable->batchCxt);
StartPortalAllocMode(DefaultAllocMode, 0);
hashtable->buckets = (HashJoinTuple *) hashtable->buckets = (HashJoinTuple *)
palloc(nbuckets * sizeof(HashJoinTuple)); palloc(nbuckets * sizeof(HashJoinTuple));
...@@ -435,9 +431,8 @@ ExecHashTableDestroy(HashJoinTable hashtable) ...@@ -435,9 +431,8 @@ ExecHashTableDestroy(HashJoinTable hashtable)
BufFileClose(hashtable->outerBatchFile[i]); BufFileClose(hashtable->outerBatchFile[i]);
} }
/* Destroy the portal to release all working memory */ /* Release working memory (batchCxt is a child, so it goes away too) */
/* cast here is a kluge for circular includes... */ MemoryContextDelete(hashtable->hashCxt);
PortalDrop((Portal *) &hashtable->myPortal);
/* And drop the control block */ /* And drop the control block */
pfree(hashtable); pfree(hashtable);
...@@ -676,11 +671,10 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples) ...@@ -676,11 +671,10 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
/* /*
* Release all the hash buckets and tuples acquired in the prior pass, * 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); oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
EndPortalAllocMode();
StartPortalAllocMode(DefaultAllocMode, 0);
/* /*
* We still use the same number of physical buckets as in the first * We still use the same number of physical buckets as in the first
......
...@@ -3,21 +3,20 @@ ...@@ -3,21 +3,20 @@
* spi.c * spi.c
* Server Programming Interface * 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 "executor/spi_priv.h"
#include "access/printtup.h" #include "access/printtup.h"
static Portal _SPI_portal = (Portal) NULL;
static _SPI_connection *_SPI_stack = NULL; static _SPI_connection *_SPI_stack = NULL;
static _SPI_connection *_SPI_current = NULL; static _SPI_connection *_SPI_current = NULL;
static int _SPI_connected = -1; static int _SPI_connected = -1;
static int _SPI_curid = -1; static int _SPI_curid = -1;
DLLIMPORT uint32 SPI_processed = 0; DLLIMPORT uint32 SPI_processed = 0;
DLLIMPORT SPITupleTable *SPI_tuptable; DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
DLLIMPORT int SPI_result; DLLIMPORT int SPI_result;
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan); static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
...@@ -46,28 +45,6 @@ extern void ShowUsage(void); ...@@ -46,28 +45,6 @@ extern void ShowUsage(void);
int int
SPI_connect() 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 * When procedure called by Executor _SPI_curid expected to be equal
* to _SPI_connected * to _SPI_connected
...@@ -99,15 +76,19 @@ SPI_connect() ...@@ -99,15 +76,19 @@ SPI_connect()
_SPI_current->processed = 0; _SPI_current->processed = 0;
_SPI_current->tuptable = NULL; _SPI_current->tuptable = NULL;
/* Create Portal for this procedure ... */ /* Create memory contexts for this procedure */
snprintf(pname, 64, "<SPI %d>", _SPI_connected); _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
_SPI_current->portal = CreatePortal(pname); "SPI Proc",
if (!PortalIsValid(_SPI_current->portal)) ALLOCSET_DEFAULT_MINSIZE,
elog(FATAL, "SPI_connect: initialization failed"); ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* ... and switch to Portal' Variable memory - procedure' context */ _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
pvmem = PortalGetVariableMemory(_SPI_current->portal); "SPI Exec",
_SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem); 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(); _SPI_current->savedId = GetScanCommandId();
SetScanCommandId(GetCurrentCommandId()); SetScanCommandId(GetCurrentCommandId());
...@@ -127,7 +108,10 @@ SPI_finish() ...@@ -127,7 +108,10 @@ SPI_finish()
/* Restore memory context as it was before procedure call */ /* Restore memory context as it was before procedure call */
MemoryContextSwitchTo(_SPI_current->savedcxt); 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); SetScanCommandId(_SPI_current->savedId);
...@@ -142,6 +126,7 @@ SPI_finish() ...@@ -142,6 +126,7 @@ SPI_finish()
{ {
free(_SPI_stack); free(_SPI_stack);
_SPI_stack = NULL; _SPI_stack = NULL;
_SPI_current = NULL;
} }
else else
{ {
...@@ -154,6 +139,25 @@ SPI_finish() ...@@ -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 void
SPI_push(void) SPI_push(void)
{ {
...@@ -508,61 +512,22 @@ SPI_palloc(Size size) ...@@ -508,61 +512,22 @@ SPI_palloc(Size size)
void * void *
SPI_repalloc(void *pointer, Size size) SPI_repalloc(void *pointer, Size size)
{ {
MemoryContext oldcxt = NULL; /* No longer need to worry which context chunk was in... */
return repalloc(pointer, size);
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;
} }
void void
SPI_pfree(void *pointer) SPI_pfree(void *pointer)
{ {
MemoryContext oldcxt = NULL; /* No longer need to worry which context chunk was in... */
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);
}
pfree(pointer); pfree(pointer);
if (oldcxt)
MemoryContextSwitchTo(oldcxt);
return;
} }
void void
SPI_freetuple(HeapTuple tuple) SPI_freetuple(HeapTuple tuple)
{ {
MemoryContext oldcxt = NULL; /* No longer need to worry which context tuple was in... */
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);
}
heap_freetuple(tuple); heap_freetuple(tuple);
if (oldcxt)
MemoryContextSwitchTo(oldcxt);
return;
} }
/* =================== private functions =================== */ /* =================== private functions =================== */
...@@ -647,7 +612,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan) ...@@ -647,7 +612,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
argtypes = plan->argtypes; 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; _SPI_current->qtlist = queryTree_list;
...@@ -790,7 +755,6 @@ static int ...@@ -790,7 +755,6 @@ static int
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
{ {
Query *parseTree = queryDesc->parsetree; Query *parseTree = queryDesc->parsetree;
Plan *plan = queryDesc->plantree;
int operation = queryDesc->operation; int operation = queryDesc->operation;
CommandDest dest = queryDesc->dest; CommandDest dest = queryDesc->dest;
TupleDesc tupdesc; TupleDesc tupdesc;
...@@ -875,16 +839,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) ...@@ -875,16 +839,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
#endif #endif
tupdesc = ExecutorStart(queryDesc, state); 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) if (isRetrieveIntoPortal)
{ {
ProcessPortal(intoName, elog(FATAL, "SPI_select: retrieve into portal not implemented");
parseTree,
plan,
state,
tupdesc,
None);
return SPI_OK_CURSOR;
} }
ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count); ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
...@@ -920,27 +881,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) ...@@ -920,27 +881,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
static MemoryContext static MemoryContext
_SPI_execmem() _SPI_execmem()
{ {
MemoryContext oldcxt; return MemoryContextSwitchTo(_SPI_current->execCxt);
PortalHeapMemory phmem;
phmem = PortalGetHeapMemory(_SPI_current->portal);
oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
return oldcxt;
} }
static MemoryContext static MemoryContext
_SPI_procmem() _SPI_procmem()
{ {
MemoryContext oldcxt; return MemoryContextSwitchTo(_SPI_current->procCxt);
PortalVariableMemory pvmem;
pvmem = PortalGetVariableMemory(_SPI_current->portal);
oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
return oldcxt;
} }
/* /*
...@@ -959,7 +906,6 @@ _SPI_begin_call(bool execmem) ...@@ -959,7 +906,6 @@ _SPI_begin_call(bool execmem)
if (execmem) /* switch to the Executor memory context */ if (execmem) /* switch to the Executor memory context */
{ {
_SPI_execmem(); _SPI_execmem();
StartPortalAllocMode(DefaultAllocMode, 0);
} }
return 0; return 0;
...@@ -977,9 +923,10 @@ _SPI_end_call(bool procmem) ...@@ -977,9 +923,10 @@ _SPI_end_call(bool procmem)
_SPI_current->qtlist = NULL; _SPI_current->qtlist = NULL;
if (procmem) /* switch to the procedure memory context */ if (procmem) /* switch to the procedure memory context */
{ /* but free Executor memory before */ {
EndPortalAllocMode();
_SPI_procmem(); _SPI_procmem();
/* and free Executor memory */
MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
} }
return 0; return 0;
...@@ -1016,8 +963,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location) ...@@ -1016,8 +963,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
MemoryContext oldcxt = NULL; MemoryContext oldcxt = NULL;
if (location == _SPI_CPLAN_PROCXT) if (location == _SPI_CPLAN_PROCXT)
oldcxt = MemoryContextSwitchTo((MemoryContext) oldcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
PortalGetVariableMemory(_SPI_current->portal));
else if (location == _SPI_CPLAN_TOPCXT) else if (location == _SPI_CPLAN_TOPCXT)
oldcxt = MemoryContextSwitchTo(TopMemoryContext); oldcxt = MemoryContextSwitchTo(TopMemoryContext);
...@@ -1033,7 +979,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location) ...@@ -1033,7 +979,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
else else
newplan->argtypes = NULL; newplan->argtypes = NULL;
if (location != _SPI_CPLAN_CURCXT) if (oldcxt != NULL)
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
return newplan; return newplan;
......
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
# Makefile for lib (miscellaneous stuff) # Makefile for lib (miscellaneous stuff)
# #
# IDENTIFICATION # 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 = ../.. SRCDIR = ../..
include ../../Makefile.global 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 all: SUBSYS.o
......
/*-------------------------------------------------------------------------
*
* 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);
}
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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) ...@@ -29,8 +29,6 @@ makeStringInfo(void)
StringInfo res; StringInfo res;
res = (StringInfo) palloc(sizeof(StringInfoData)); res = (StringInfo) palloc(sizeof(StringInfoData));
if (res == NULL)
elog(ERROR, "makeStringInfo: Out of memory");
initStringInfo(res); initStringInfo(res);
...@@ -49,9 +47,6 @@ initStringInfo(StringInfo str) ...@@ -49,9 +47,6 @@ initStringInfo(StringInfo str)
int size = 256; /* initial default buffer size */ int size = 256; /* initial default buffer size */
str->data = (char *) palloc(size); str->data = (char *) palloc(size);
if (str->data == NULL)
elog(ERROR,
"initStringInfo: Out of memory (%d bytes requested)", size);
str->maxlen = size; str->maxlen = size;
str->len = 0; str->len = 0;
str->data[0] = '\0'; str->data[0] = '\0';
...@@ -62,6 +57,11 @@ initStringInfo(StringInfo str) ...@@ -62,6 +57,11 @@ initStringInfo(StringInfo str)
* *
* Internal routine: make sure there is enough space for 'needed' more bytes * Internal routine: make sure there is enough space for 'needed' more bytes
* ('needed' does not include the terminating null). * ('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 static void
enlargeStringInfo(StringInfo str, int needed) enlargeStringInfo(StringInfo str, int needed)
...@@ -83,9 +83,6 @@ enlargeStringInfo(StringInfo str, int needed) ...@@ -83,9 +83,6 @@ enlargeStringInfo(StringInfo str, int needed)
newlen = 2 * newlen; newlen = 2 * newlen;
str->data = (char *) repalloc(str->data, 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; str->maxlen = newlen;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This should be moved to a more appropriate place. It is here * This should be moved to a more appropriate place. It is here
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* Builtin functions for open/close/read/write operations on large objects. * 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 large object descriptors hang around until we destroy the context.
* That happens in lo_commit(). It'd be possible to prolong the lifetime * 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, * of the context so that LO FDs are good across transactions (for example,
...@@ -24,8 +24,10 @@ ...@@ -24,8 +24,10 @@
* But we'd need additional state in order to do the right thing at the * 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 * 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 * 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 * relations at all. Locking semantics are also an interesting problem
* semantics of LO FDs: they're only good within a transaction. * 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 @@ ...@@ -56,7 +58,7 @@
*/ */
static LargeObjectDesc *cookies[MAX_LOBJ_FDS]; static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
static GlobalMemory fscxt = NULL; static MemoryContext fscxt = NULL;
static int newLOfd(LargeObjectDesc *lobjCookie); static int newLOfd(LargeObjectDesc *lobjCookie);
...@@ -80,8 +82,13 @@ lo_open(PG_FUNCTION_ARGS) ...@@ -80,8 +82,13 @@ lo_open(PG_FUNCTION_ARGS)
#endif #endif
if (fscxt == NULL) if (fscxt == NULL)
fscxt = CreateGlobalMemory("Filesystem"); fscxt = AllocSetContextCreate(TopMemoryContext,
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt); "Filesystem",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
currentContext = MemoryContextSwitchTo(fscxt);
lobjDesc = inv_open(lobjId, mode); lobjDesc = inv_open(lobjId, mode);
...@@ -128,7 +135,7 @@ lo_close(PG_FUNCTION_ARGS) ...@@ -128,7 +135,7 @@ lo_close(PG_FUNCTION_ARGS)
#endif #endif
Assert(fscxt != NULL); Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt); currentContext = MemoryContextSwitchTo(fscxt);
inv_close(cookies[fd]); inv_close(cookies[fd]);
...@@ -166,7 +173,7 @@ lo_read(int fd, char *buf, int len) ...@@ -166,7 +173,7 @@ lo_read(int fd, char *buf, int len)
} }
Assert(fscxt != NULL); Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt); currentContext = MemoryContextSwitchTo(fscxt);
status = inv_read(cookies[fd], buf, len); status = inv_read(cookies[fd], buf, len);
...@@ -193,7 +200,7 @@ lo_write(int fd, char *buf, int len) ...@@ -193,7 +200,7 @@ lo_write(int fd, char *buf, int len)
} }
Assert(fscxt != NULL); Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt); currentContext = MemoryContextSwitchTo(fscxt);
status = inv_write(cookies[fd], buf, len); status = inv_write(cookies[fd], buf, len);
...@@ -224,7 +231,7 @@ lo_lseek(PG_FUNCTION_ARGS) ...@@ -224,7 +231,7 @@ lo_lseek(PG_FUNCTION_ARGS)
} }
Assert(fscxt != NULL); Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt); currentContext = MemoryContextSwitchTo(fscxt);
status = inv_seek(cookies[fd], offset, whence); status = inv_seek(cookies[fd], offset, whence);
...@@ -242,9 +249,13 @@ lo_creat(PG_FUNCTION_ARGS) ...@@ -242,9 +249,13 @@ lo_creat(PG_FUNCTION_ARGS)
Oid lobjId; Oid lobjId;
if (fscxt == NULL) 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); lobjDesc = inv_create(mode);
...@@ -493,7 +504,7 @@ lo_commit(bool isCommit) ...@@ -493,7 +504,7 @@ lo_commit(bool isCommit)
if (fscxt == NULL) if (fscxt == NULL)
return; /* no LO operations in this xact */ 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 * Clean out still-open index scans (not necessary if aborting) and
...@@ -512,7 +523,7 @@ lo_commit(bool isCommit) ...@@ -512,7 +523,7 @@ lo_commit(bool isCommit)
MemoryContextSwitchTo(currentContext); MemoryContextSwitchTo(currentContext);
/* Release the LO memory context to prevent permanent memory leaks. */ /* Release the LO memory context to prevent permanent memory leaks. */
GlobalMemoryDestroy(fscxt); MemoryContextDelete(fscxt);
fscxt = NULL; fscxt = NULL;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -135,9 +135,11 @@ PQexec(char *query)
/* ---------------- /* ----------------
* pg_exec_query_dest will put the query results in a portal which will * pg_exec_query_dest will put the query results in a portal which will
* end up on the top of the portal stack. * 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 * pop the portal off the portal stack and return the
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This shouldn't be in libpq, but the monitor and some other * This shouldn't be in libpq, but the monitor and some other
...@@ -44,6 +44,44 @@ ...@@ -44,6 +44,44 @@
#include "libpq/pqsignal.h" #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 pqsigfunc
pqsignal(int signo, pqsigfunc func) pqsignal(int signo, pqsigfunc func)
{ {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -19,9 +19,9 @@
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/ */
#include <math.h>
#include "postgres.h" #include "postgres.h"
#include <math.h>
#ifdef HAVE_LIMITS_H #ifdef HAVE_LIMITS_H
#include <limits.h> #include <limits.h>
#else #else
...@@ -33,41 +33,8 @@ ...@@ -33,41 +33,8 @@
#include "optimizer/geqo.h" #include "optimizer/geqo.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
#include "utils/portal.h" #include "utils/memutils.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));
}
geqo_eval_context = (MemoryContext) PortalGetHeapMemory(geqo_portal);
}
/* /*
* geqo_eval * geqo_eval
...@@ -77,20 +44,30 @@ geqo_eval_startup(void) ...@@ -77,20 +44,30 @@ geqo_eval_startup(void)
Cost Cost
geqo_eval(Query *root, Gene *tour, int num_gene) geqo_eval(Query *root, Gene *tour, int num_gene)
{ {
MemoryContext mycontext;
MemoryContext oldcxt; MemoryContext oldcxt;
RelOptInfo *joinrel; RelOptInfo *joinrel;
Cost fitness; Cost fitness;
List *savelist; 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 * Create a private memory context that will hold all temp storage
* work * 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); mycontext = AllocSetContextCreate(TransactionCommandContext,
StartPortalAllocMode(DefaultAllocMode, 0); "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 */ /* construct the best path for the given combination of relations */
joinrel = gimme_tree(root, tour, 0, num_gene, NULL); joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
...@@ -107,8 +84,8 @@ geqo_eval(Query *root, Gene *tour, int num_gene) ...@@ -107,8 +84,8 @@ geqo_eval(Query *root, Gene *tour, int num_gene)
root->join_rel_list = savelist; root->join_rel_list = savelist;
/* release all the memory acquired within gimme_tree */ /* release all the memory acquired within gimme_tree */
EndPortalAllocMode();
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
MemoryContextDelete(mycontext);
return fitness; return fitness;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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) ...@@ -110,9 +110,6 @@ geqo(Query *root)
else else
srandom(time(NULL)); srandom(time(NULL));
/* initialize plan evaluator */
geqo_eval_startup();
/* allocate genetic pool memory */ /* allocate genetic pool memory */
pool = alloc_pool(pool_size, number_of_rels); pool = alloc_pool(pool_size, number_of_rels);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -378,15 +378,38 @@ PostmasterMain(int argc, char *argv[]) ...@@ -378,15 +378,38 @@ PostmasterMain(int argc, char *argv[])
*/ */
umask((mode_t) 0077); umask((mode_t) 0077);
ResetAllOptions();
MyProcPid = getpid(); 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")) if (getenv("PGDATA"))
DataDir = strdup(getenv("PGDATA")); /* default value */ DataDir = strdup(getenv("PGDATA")); /* default value */
if (getenv("PGPORT")) if (getenv("PGPORT"))
PostPortName = atoi(getenv("PGPORT")); PostPortName = atoi(getenv("PGPORT"));
ResetAllOptions();
/* /*
* First we must scan for a -D argument to get the data dir. Then * First we must scan for a -D argument to get the data dir. Then
* read the config file. Finally, scan all the other arguments. * read the config file. Finally, scan all the other arguments.
...@@ -600,7 +623,6 @@ PostmasterMain(int argc, char *argv[]) ...@@ -600,7 +623,6 @@ PostmasterMain(int argc, char *argv[])
} }
#endif #endif
/* set up shared memory and semaphores */ /* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
reset_shared(PostPortName); reset_shared(PostPortName);
/* /*
...@@ -662,7 +684,7 @@ PostmasterMain(int argc, char *argv[]) ...@@ -662,7 +684,7 @@ PostmasterMain(int argc, char *argv[])
/* /*
* Set up signal handlers for the postmaster process. * Set up signal handlers for the postmaster process.
*/ */
PG_INITMASK(); pqinitmask();
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have children do same */ pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have children do same */
...@@ -1867,6 +1889,7 @@ DoBackend(Port *port) ...@@ -1867,6 +1889,7 @@ DoBackend(Port *port)
/* Save port etc. for ps status */ /* Save port etc. for ps status */
MyProcPort = port; MyProcPort = port;
/* Reset MyProcPid to new backend's pid */
MyProcPid = getpid(); MyProcPid = getpid();
/* /*
...@@ -1946,6 +1969,19 @@ DoBackend(Port *port) ...@@ -1946,6 +1969,19 @@ DoBackend(Port *port)
av[ac] = (char *) NULL; 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) if (DebugLvl > 1)
{ {
fprintf(stderr, "%s child[%d]: starting with (", fprintf(stderr, "%s child[%d]: starting with (",
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -16,51 +16,20 @@
#include "postgres.h" #include "postgres.h"
#include "access/heapam.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 "parser/parse_relation.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteSupport.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 - * InsertRule -
* takes the arguments and inserts them as attributes into the system * takes the arguments and inserts them as attributes into the system
* relation "pg_rewrite" * relation "pg_rewrite"
* *
* MODS : changes the value of LastOidProcessed as a side
* effect of inserting the rule tuple
*
* ARGS : rulname - name of the rule * ARGS : rulname - name of the rule
* evtype - one of RETRIEVE,REPLACE,DELETE,APPEND * evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
* evobj - name of relation * evobj - name of relation
...@@ -78,11 +47,17 @@ InsertRule(char *rulname, ...@@ -78,11 +47,17 @@ InsertRule(char *rulname,
bool evinstead, bool evinstead,
char *actiontree) char *actiontree)
{ {
StringInfoData rulebuf;
Relation eventrel; Relation eventrel;
Oid eventrel_oid; Oid eventrel_oid;
AttrNumber evslot_index; 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 = heap_openr(evobj, AccessShareLock);
eventrel_oid = RelationGetRelid(eventrel); eventrel_oid = RelationGetRelid(eventrel);
...@@ -96,9 +71,6 @@ InsertRule(char *rulname, ...@@ -96,9 +71,6 @@ InsertRule(char *rulname,
evslot_index = attnameAttNum(eventrel, evslot); evslot_index = attnameAttNum(eventrel, evslot);
heap_close(eventrel, AccessShareLock); heap_close(eventrel, AccessShareLock);
if (evinstead)
is_instead = "t";
if (evqual == NULL) if (evqual == NULL)
evqual = "<>"; evqual = "<>";
...@@ -106,23 +78,54 @@ InsertRule(char *rulname, ...@@ -106,23 +78,54 @@ InsertRule(char *rulname,
elog(ERROR, "Attempt to insert rule '%s' failed: already exists", elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
rulname); rulname);
initStringInfo(&rulebuf); /* ----------------
appendStringInfo(&rulebuf, * Set up *nulls and *values arrays
"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, ", MemSet(nulls, ' ', sizeof(nulls));
evtype, eventrel_oid, evslot_index);
quoteString(&rulebuf, actiontree); i = 0;
appendStringInfo(&rulebuf, "::text, "); namestrcpy(&rname, rulname);
quoteString(&rulebuf, evqual); values[i++] = NameGetDatum(&rname);
appendStringInfo(&rulebuf, "::text, '%s'::bool);", values[i++] = CharGetDatum(evtype + '0');
is_instead); 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;
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -136,7 +136,7 @@ prs2_addToRelation(Oid relid,
* create an in memory RewriteRule data structure which is cached by * create an in memory RewriteRule data structure which is cached by
* every Relation descriptor. (see utils/cache/relcache.c) * every Relation descriptor. (see utils/cache/relcache.c)
*/ */
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
thisRule = (RewriteRule *) palloc(sizeof(RewriteRule)); thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
if (qual != NULL) if (qual != NULL)
qual = copyObject(qual); qual = copyObject(qual);
...@@ -159,7 +159,7 @@ prs2_addToRelation(Oid relid, ...@@ -159,7 +159,7 @@ prs2_addToRelation(Oid relid,
if (relation->rd_rules == NULL) if (relation->rd_rules == NULL)
{ {
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
rulelock = (RuleLock *) palloc(sizeof(RuleLock)); rulelock = (RuleLock *) palloc(sizeof(RuleLock));
rulelock->numLocks = 1; rulelock->numLocks = 1;
rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *)); rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
...@@ -181,7 +181,7 @@ prs2_addToRelation(Oid relid, ...@@ -181,7 +181,7 @@ prs2_addToRelation(Oid relid,
rulelock = relation->rd_rules; rulelock = relation->rd_rules;
numlock = rulelock->numLocks; numlock = rulelock->numLocks;
/* expand, for safety reasons */ /* expand, for safety reasons */
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
rulelock->rules = (RewriteRule **) repalloc(rulelock->rules, rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
sizeof(RewriteRule *) * (numlock + 1)); sizeof(RewriteRule *) * (numlock + 1));
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
...@@ -212,7 +212,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId) ...@@ -212,7 +212,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
break; break;
} }
Assert(i < numlock); Assert(i < numlock);
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
pfree(rulelock->rules[i]); pfree(rulelock->rules[i]);
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
if (numlock == 1) if (numlock == 1)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -262,29 +262,23 @@ InitShmem(unsigned int key, unsigned int size)
} }
/* /*
* ShmemAlloc -- allocate word-aligned byte string from * ShmemAlloc -- allocate max-aligned byte string from shared memory
* shared memory
* *
* Assumes ShmemLock and ShmemFreeStart are initialized. * Assumes ShmemLock and ShmemFreeStart are initialized.
* Returns: real pointer to memory or NULL if we are out * Returns: real pointer to memory or NULL if we are out
* of space. Has to return a real pointer in order * of space. Has to return a real pointer in order
* to be compatable with malloc(). * to be compatible with malloc().
*/ */
long * void *
ShmemAlloc(unsigned long size) ShmemAlloc(Size size)
{ {
unsigned long tmpFree; unsigned long tmpFree;
long *newSpace; void *newSpace;
/* /*
* ensure space is word aligned. * ensure all space is adequately 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
*/ */
if (size % sizeof(double)) size = MAXALIGN(size);
size += sizeof(double) - (size % sizeof(double));
Assert(*ShmemFreeStart); Assert(*ShmemFreeStart);
...@@ -293,7 +287,7 @@ ShmemAlloc(unsigned long size) ...@@ -293,7 +287,7 @@ ShmemAlloc(unsigned long size)
tmpFree = *ShmemFreeStart + size; tmpFree = *ShmemFreeStart + size;
if (tmpFree <= ShmemSize) if (tmpFree <= ShmemSize)
{ {
newSpace = (long *) MAKE_PTR(*ShmemFreeStart); newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
*ShmemFreeStart += size; *ShmemFreeStart += size;
} }
else else
...@@ -302,7 +296,8 @@ ShmemAlloc(unsigned long size) ...@@ -302,7 +296,8 @@ ShmemAlloc(unsigned long size)
SpinRelease(ShmemLock); SpinRelease(ShmemLock);
if (!newSpace) if (!newSpace)
elog(NOTICE, "ShmemAlloc: out of memory "); elog(NOTICE, "ShmemAlloc: out of memory");
return newSpace; return newSpace;
} }
...@@ -336,7 +331,7 @@ ShmemInitHash(char *name, /* table string name for shmem index */ ...@@ -336,7 +331,7 @@ ShmemInitHash(char *name, /* table string name for shmem index */
int hash_flags) /* info about infoP */ int hash_flags) /* info about infoP */
{ {
bool found; bool found;
long *location; void *location;
/* /*
* Hash tables allocated in shared memory have a fixed directory; it * Hash tables allocated in shared memory have a fixed directory; it
...@@ -478,12 +473,12 @@ ShmemPIDDestroy(int pid) ...@@ -478,12 +473,12 @@ ShmemPIDDestroy(int pid)
* the object is already in the shmem index (hence, already * the object is already in the shmem index (hence, already
* initialized). * initialized).
*/ */
long * void *
ShmemInitStruct(char *name, unsigned long size, bool *foundPtr) ShmemInitStruct(char *name, Size size, bool *foundPtr)
{ {
ShmemIndexEnt *result, ShmemIndexEnt *result,
item; item;
long *structPtr; void *structPtr;
strncpy(item.key, name, SHMEM_INDEX_KEYSIZE); strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
item.location = BAD_LOCATION; item.location = BAD_LOCATION;
...@@ -498,27 +493,27 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr) ...@@ -498,27 +493,27 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
#endif #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() * If we are creating the first shmem index, then let shmemalloc()
* allocate the space for a new HTAB. Otherwise, find the old one * allocate the space for a new HTAB. Otherwise, find the old one
* and return that. Notice that the ShmemIndexLock is held until * and return that. Notice that the ShmemIndexLock is held until
* the shmem index has been completely initialized. * the shmem index has been completely initialized.
*/ */
Assert(!strcmp(name, strname)); Assert(strcmp(name, strname) == 0);
if (ShmemBootstrap) if (ShmemBootstrap)
{ {
/* in POSTMASTER/Single process */ /* in POSTMASTER/Single process */
*foundPtr = FALSE; *foundPtr = FALSE;
return (long *) ShmemAlloc(size); return ShmemAlloc(size);
} }
else else
{ {
Assert(ShmemIndexOffset); Assert(ShmemIndexOffset);
*foundPtr = TRUE; *foundPtr = TRUE;
return (long *) MAKE_PTR(*ShmemIndexOffset); return (void *) MAKE_PTR(*ShmemIndexOffset);
} }
...@@ -554,12 +549,12 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr) ...@@ -554,12 +549,12 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
/* let caller print its message too */ /* let caller print its message too */
return NULL; return NULL;
} }
structPtr = (long *) MAKE_PTR(result->location); structPtr = (void *) MAKE_PTR(result->location);
} }
else else
{ {
/* It isn't in the table yet. allocate and initialize it */ /* It isn't in the table yet. allocate and initialize it */
structPtr = ShmemAlloc((long) size); structPtr = ShmemAlloc(size);
if (!structPtr) if (!structPtr)
{ {
/* out of memory */ /* out of memory */
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -1090,7 +1090,7 @@ inv_newtuple(LargeObjectDesc *obj_desc,
ntup->t_len = tupsize; ntup->t_len = tupsize;
ItemPointerSet(&ntup->t_self, BufferGetBlockNumber(buffer), off); 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)); TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_data->t_xmin));
ntup->t_data->t_cmin = GetCurrentCommandId(); ntup->t_data->t_cmin = GetCurrentCommandId();
StoreInvalidTransactionId(&(ntup->t_data->t_xmax)); StoreInvalidTransactionId(&(ntup->t_data->t_xmax));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Outside modules can create a lock table and acquire/release * Outside modules can create a lock table and acquire/release
...@@ -225,6 +225,11 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable, ...@@ -225,6 +225,11 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable,
* has its name stored in the shmem index at its creation. It * has its name stored in the shmem index at its creation. It
* is wasteful, in this case, but not much space is involved. * 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 LOCKMETHOD
LockMethodTableInit(char *tabName, LockMethodTableInit(char *tabName,
...@@ -246,22 +251,13 @@ LockMethodTableInit(char *tabName, ...@@ -246,22 +251,13 @@ LockMethodTableInit(char *tabName,
return INVALID_LOCKMETHOD; return INVALID_LOCKMETHOD;
} }
/* allocate a string for the shmem index table lookup */ /* Allocate a string for the shmem index table lookups. */
shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32)); /* This is just temp space in this routine, so palloc is OK. */
if (!shmemName) shmemName = (char *) palloc(strlen(tabName) + 32);
{
elog(NOTICE, "LockMethodTableInit: couldn't malloc string %s \n", tabName);
return INVALID_LOCKMETHOD;
}
/* each lock table has a non-shared header */ /* each lock table has a non-shared, permanent header */
lockMethodTable = (LOCKMETHODTABLE *) palloc((unsigned) sizeof(LOCKMETHODTABLE)); lockMethodTable = (LOCKMETHODTABLE *)
if (!lockMethodTable) MemoryContextAlloc(TopMemoryContext, sizeof(LOCKMETHODTABLE));
{
elog(NOTICE, "LockMethodTableInit: couldn't malloc lock table %s\n", tabName);
pfree(shmemName);
return INVALID_LOCKMETHOD;
}
/* ------------------------ /* ------------------------
* find/acquire the spinlock for the table * find/acquire the spinlock for the table
...@@ -269,7 +265,6 @@ LockMethodTableInit(char *tabName, ...@@ -269,7 +265,6 @@ LockMethodTableInit(char *tabName,
*/ */
SpinAcquire(LockMgrLock); SpinAcquire(LockMgrLock);
/* ----------------------- /* -----------------------
* allocate a control structure from shared memory or attach to it * allocate a control structure from shared memory or attach to it
* if it already exists. * if it already exists.
...@@ -277,7 +272,7 @@ LockMethodTableInit(char *tabName, ...@@ -277,7 +272,7 @@ LockMethodTableInit(char *tabName,
*/ */
sprintf(shmemName, "%s (ctl)", tabName); sprintf(shmemName, "%s (ctl)", tabName);
lockMethodTable->ctl = (LOCKMETHODCTL *) lockMethodTable->ctl = (LOCKMETHODCTL *)
ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found); ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
if (!lockMethodTable->ctl) if (!lockMethodTable->ctl)
{ {
...@@ -910,7 +905,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode) ...@@ -910,7 +905,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode); LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode);
old_status = pstrdup(get_ps_display()); 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()); strcpy(new_status, get_ps_display());
strcat(new_status, " waiting"); strcat(new_status, " waiting");
set_ps_display(new_status); set_ps_display(new_status);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -47,7 +47,7 @@
* This is so that we can support more backends. (system-wide semaphore * This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95 * 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 <sys/time.h>
#include <unistd.h> #include <unistd.h>
...@@ -119,7 +119,7 @@ InitProcGlobal(IPCKey key, int maxBackends) ...@@ -119,7 +119,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
/* attach to the free list */ /* attach to the free list */
ProcGlobal = (PROC_HDR *) ProcGlobal = (PROC_HDR *)
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found); ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
/* -------------------- /* --------------------
* We're the first - initialize. * We're the first - initialize.
...@@ -185,7 +185,7 @@ InitProcess(IPCKey key) ...@@ -185,7 +185,7 @@ InitProcess(IPCKey key)
/* attach to the free list */ /* attach to the free list */
ProcGlobal = (PROC_HDR *) ProcGlobal = (PROC_HDR *)
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found); ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
if (!found) if (!found)
{ {
/* this should not happen. InitProcGlobal() is called before this. */ /* this should not happen. InitProcGlobal() is called before this. */
...@@ -218,7 +218,7 @@ InitProcess(IPCKey key) ...@@ -218,7 +218,7 @@ InitProcess(IPCKey key)
* cleanup dead processes). * cleanup dead processes).
*/ */
MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC)); MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
if (!MyProc) if (!MyProc)
{ {
SpinRelease(ProcStructLock); SpinRelease(ProcStructLock);
...@@ -458,7 +458,7 @@ ProcQueueAlloc(char *name) ...@@ -458,7 +458,7 @@ ProcQueueAlloc(char *name)
{ {
bool found; bool found;
PROC_QUEUE *queue = (PROC_QUEUE *) PROC_QUEUE *queue = (PROC_QUEUE *)
ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found); ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
if (!queue) if (!queue)
return NULL; return NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -94,19 +94,15 @@ static BlockNumber _mdnblocks(File file, Size blcksz);
int int
mdinit() mdinit()
{ {
MemoryContext oldcxt;
int i; int i;
MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr"); MdCxt = AllocSetContextCreate(TopMemoryContext,
if (MdCxt == (MemoryContext) NULL) "MdSmgr",
return SM_FAIL; ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
oldcxt = MemoryContextSwitchTo(MdCxt); ALLOCSET_DEFAULT_MAXSIZE);
Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
MemoryContextSwitchTo(oldcxt);
if (Md_fdvec == (MdfdVec *) NULL) Md_fdvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
return SM_FAIL;
MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec)); MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
...@@ -208,7 +204,6 @@ mdunlink(Relation reln) ...@@ -208,7 +204,6 @@ mdunlink(Relation reln)
int nblocks; int nblocks;
int fd; int fd;
MdfdVec *v; MdfdVec *v;
MemoryContext oldcxt;
/* /*
* If the relation is already unlinked,we have nothing to do any more. * If the relation is already unlinked,we have nothing to do any more.
...@@ -238,7 +233,6 @@ mdunlink(Relation reln) ...@@ -238,7 +233,6 @@ mdunlink(Relation reln)
Md_fdvec[fd].mdfd_flags = (uint16) 0; Md_fdvec[fd].mdfd_flags = (uint16) 0;
oldcxt = MemoryContextSwitchTo(MdCxt);
#ifndef LET_OS_MANAGE_FILESIZE #ifndef LET_OS_MANAGE_FILESIZE
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;) for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
{ {
...@@ -256,7 +250,6 @@ mdunlink(Relation reln) ...@@ -256,7 +250,6 @@ mdunlink(Relation reln)
FileTruncate(v->mdfd_vfd, 0); FileTruncate(v->mdfd_vfd, 0);
FileUnlink(v->mdfd_vfd); FileUnlink(v->mdfd_vfd);
#endif #endif
MemoryContextSwitchTo(oldcxt);
_fdvec_free(fd); _fdvec_free(fd);
...@@ -400,9 +393,7 @@ static void ...@@ -400,9 +393,7 @@ static void
mdclose_fd(int fd) mdclose_fd(int fd)
{ {
MdfdVec *v; MdfdVec *v;
MemoryContext oldcxt;
oldcxt = MemoryContextSwitchTo(MdCxt);
#ifndef LET_OS_MANAGE_FILESIZE #ifndef LET_OS_MANAGE_FILESIZE
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;) for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
{ {
...@@ -446,7 +437,6 @@ mdclose_fd(int fd) ...@@ -446,7 +437,6 @@ mdclose_fd(int fd)
} }
} }
#endif #endif
MemoryContextSwitchTo(oldcxt);
_fdvec_free(fd); _fdvec_free(fd);
} }
...@@ -751,11 +741,8 @@ mdtruncate(Relation reln, int nblocks) ...@@ -751,11 +741,8 @@ mdtruncate(Relation reln, int nblocks)
int curnblk; int curnblk;
int fd; int fd;
MdfdVec *v; MdfdVec *v;
#ifndef LET_OS_MANAGE_FILESIZE #ifndef LET_OS_MANAGE_FILESIZE
MemoryContext oldcxt;
int priorblocks; int priorblocks;
#endif #endif
/* /*
...@@ -772,7 +759,6 @@ mdtruncate(Relation reln, int nblocks) ...@@ -772,7 +759,6 @@ mdtruncate(Relation reln, int nblocks)
v = &Md_fdvec[fd]; v = &Md_fdvec[fd];
#ifndef LET_OS_MANAGE_FILESIZE #ifndef LET_OS_MANAGE_FILESIZE
oldcxt = MemoryContextSwitchTo(MdCxt);
priorblocks = 0; priorblocks = 0;
while (v != (MdfdVec *) NULL) while (v != (MdfdVec *) NULL)
{ {
...@@ -825,7 +811,6 @@ mdtruncate(Relation reln, int nblocks) ...@@ -825,7 +811,6 @@ mdtruncate(Relation reln, int nblocks)
} }
priorblocks += RELSEG_SIZE; priorblocks += RELSEG_SIZE;
} }
MemoryContextSwitchTo(oldcxt);
#else #else
if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0) if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
return -1; return -1;
...@@ -833,8 +818,7 @@ mdtruncate(Relation reln, int nblocks) ...@@ -833,8 +818,7 @@ mdtruncate(Relation reln, int nblocks)
#endif #endif
return nblocks; return nblocks;
}
} /* mdtruncate */
/* /*
* mdcommit() -- Commit a transaction. * mdcommit() -- Commit a transaction.
...@@ -907,7 +891,6 @@ _fdvec_alloc() ...@@ -907,7 +891,6 @@ _fdvec_alloc()
MdfdVec *nvec; MdfdVec *nvec;
int fdvec, int fdvec,
i; i;
MemoryContext oldcxt;
if (Md_Free >= 0) /* get from free list */ if (Md_Free >= 0) /* get from free list */
{ {
...@@ -930,15 +913,11 @@ _fdvec_alloc() ...@@ -930,15 +913,11 @@ _fdvec_alloc()
Nfds *= 2; Nfds *= 2;
oldcxt = MemoryContextSwitchTo(MdCxt); nvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
MemSet(nvec, 0, 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); pfree(Md_fdvec);
MemoryContextSwitchTo(oldcxt);
Md_fdvec = nvec; Md_fdvec = nvec;
/* Set new free list */ /* Set new free list */
...@@ -976,7 +955,6 @@ _fdvec_free(int fdvec) ...@@ -976,7 +955,6 @@ _fdvec_free(int fdvec)
static MdfdVec * static MdfdVec *
_mdfd_openseg(Relation reln, int segno, int oflags) _mdfd_openseg(Relation reln, int segno, int oflags)
{ {
MemoryContext oldcxt;
MdfdVec *v; MdfdVec *v;
int fd; int fd;
char *path, char *path,
...@@ -1003,9 +981,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags) ...@@ -1003,9 +981,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags)
return (MdfdVec *) NULL; return (MdfdVec *) NULL;
/* allocate an mdfdvec entry for it */ /* allocate an mdfdvec entry for it */
oldcxt = MemoryContextSwitchTo(MdCxt); v = (MdfdVec *) MemoryContextAlloc(MdCxt, sizeof(MdfdVec));
v = (MdfdVec *) palloc(sizeof(MdfdVec));
MemoryContextSwitchTo(oldcxt);
/* fill the entry */ /* fill the entry */
v->mdfd_vfd = fd; v->mdfd_vfd = fd;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -79,7 +79,6 @@ bool Log_connections = false; ...@@ -79,7 +79,6 @@ bool Log_connections = false;
CommandDest whereToSendOutput = Debug; CommandDest whereToSendOutput = Debug;
extern void BaseInit(void);
extern void StartupXLOG(void); extern void StartupXLOG(void);
extern void ShutdownXLOG(void); extern void ShutdownXLOG(void);
...@@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS); ...@@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS);
extern char XLogDir[]; extern char XLogDir[];
extern char ControlFilePath[]; extern char ControlFilePath[];
extern int lockingOff; static bool dontExecute = false;
extern int NBuffers;
int dontExecute = 0;
static bool IsEmptyQuery = false; static bool IsEmptyQuery = false;
/* note: these declarations had better match tcopprot.h */ /* note: these declarations had better match tcopprot.h */
...@@ -101,8 +98,6 @@ bool Warn_restart_ready = false; ...@@ -101,8 +98,6 @@ bool Warn_restart_ready = false;
bool InError = false; bool InError = false;
bool ExitAfterAbort = false; bool ExitAfterAbort = false;
extern int NBuffers;
static bool EchoQuery = false; /* default don't echo */ static bool EchoQuery = false; /* default don't echo */
char pg_pathname[MAXPGPATH]; char pg_pathname[MAXPGPATH];
FILE *StatFp = NULL; FILE *StatFp = NULL;
...@@ -133,7 +128,6 @@ int XfuncMode = 0; ...@@ -133,7 +128,6 @@ int XfuncMode = 0;
static int InteractiveBackend(StringInfo inBuf); static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(StringInfo inBuf); static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf); static int ReadCommand(StringInfo inBuf);
static void pg_exec_query(char *query_string);
static void SigHupHandler(SIGNAL_ARGS); static void SigHupHandler(SIGNAL_ARGS);
static void FloatExceptionHandler(SIGNAL_ARGS); static void FloatExceptionHandler(SIGNAL_ARGS);
static void quickdie(SIGNAL_ARGS); static void quickdie(SIGNAL_ARGS);
...@@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf) ...@@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf)
static int static int
ReadCommand(StringInfo inBuf) ReadCommand(StringInfo inBuf)
{ {
MemoryContext oldcontext;
int result; 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) if (IsUnderPostmaster)
result = SocketBackend(inBuf); result = SocketBackend(inBuf);
else else
result = InteractiveBackend(inBuf); result = InteractiveBackend(inBuf);
MemoryContextSwitchTo(oldcontext);
return result; return result;
} }
...@@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf) ...@@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf)
* multiple queries and/or the rewriter might expand one query to several. * multiple queries and/or the rewriter might expand one query to several.
*/ */
List * List *
pg_parse_and_rewrite(char *query_string, /* string to execute */ pg_parse_and_rewrite(char *query_string, /* string to execute */
Oid *typev,/* argument types */ Oid *typev, /* parameter types */
int nargs, /* number of arguments */ int nargs) /* number of parameters */
bool aclOverride)
{ {
List *querytree_list; List *querytree_list;
List *querytree_list_item; List *querytree_list_item;
...@@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */ ...@@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
querytree_list = new_list; 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_print_rewritten)
{ {
if (Debug_pretty_print) if (Debug_pretty_print)
...@@ -516,63 +478,66 @@ pg_plan_query(Query *querytree) ...@@ -516,63 +478,66 @@ pg_plan_query(Query *querytree)
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* pg_exec_query() * pg_exec_query_dest()
* *
* Takes a querystring, runs the parser/utilities or * Takes a querystring, runs the parser/utilities or
* parser/planner/executor over it as necessary * parser/planner/executor over it as necessary.
* Begin Transaction Should have been called before this *
* and CommitTransaction After this is called * Assumptions:
* This is strictly because we do not allow for nested xactions. *
* 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 * parse_context references a context suitable for holding the
* this function _MUST_ allocate a new "parsetree" each time, * parse/rewrite trees (typically this will be QueryContext).
* since it may be stored in a named portal and should not * This context must be longer-lived than the CurrentMemoryContext!
* change its value. * 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 void
pg_exec_query_dest(char *query_string, /* string to execute */ pg_exec_query_dest(char *query_string, /* string to execute */
CommandDest dest, /* where results should go */ CommandDest dest, /* where results should go */
bool aclOverride) /* to give utility commands power MemoryContext parse_context) /* context for parsetrees */
* of superusers */
{ {
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, * Switch to appropriate context for constructing parsetrees.
aclOverride); */
oldcontext = MemoryContextSwitchTo(parse_context);
/* /*
* NOTE: we do not use "foreach" here because we want to be sure the * Parse and rewrite the query or queries.
* 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.
*/ */
while (querytree_list) querytree_list = pg_parse_and_rewrite(query_string, NULL, 0);
{
Query *querytree = (Query *) lfirst(querytree_list);
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 we got a cancel signal in parsing or prior command, quit */
if (QueryCancel) if (QueryCancel)
...@@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string, /* string to execute */ ...@@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string, /* string to execute */
if (Show_executor_stats) if (Show_executor_stats)
ResetUsage(); ResetUsage();
if (DebugLvl > 1) if (dontExecute)
elog(DEBUG, "ProcessQuery"); {
ProcessQuery(querytree, plan, dest); /* 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) if (Show_executor_stats)
{ {
...@@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string, /* string to execute */ ...@@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string, /* string to execute */
* between queries so that the effects of early queries are * between queries so that the effects of early queries are
* visible to subsequent ones. * visible to subsequent ones.
*/ */
CommandCounterIncrement(); 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[]) ...@@ -821,6 +801,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
extern char *optarg; extern char *optarg;
extern int DebugLvl; 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. * Set default values for command-line options.
*/ */
...@@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
break; break;
case 'i': case 'i':
dontExecute = 1; dontExecute = true;
break; break;
case 'L': case 'L':
...@@ -1182,11 +1173,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -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. * Note that postmaster already blocked ALL signals to make us happy.
*/ */
if (!IsUnderPostmaster) pqinitmask();
{
PG_INITMASK();
PG_SETMASK(&BlockSig);
}
#ifdef HAVE_SIGPROCMASK #ifdef HAVE_SIGPROCMASK
sigdelset(&BlockSig, SIGUSR1); sigdelset(&BlockSig, SIGUSR1);
...@@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
BlockSig &= ~(sigmask(SIGUSR1)); BlockSig &= ~(sigmask(SIGUSR1));
#endif #endif
PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */ pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */ pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
pqsignal(SIGQUIT, handle_warn); /* handle error */ pqsignal(SIGQUIT, handle_warn); /* handle error */
...@@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL);
pqsignal(SIGCONT, 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) * Get user name (needed now in case it is the default database name)
* and check command line validity * and check command line validity
...@@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
on_shmem_exit(remove_all_temp_relations, NULL); 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. * Send this backend's cancellation info to the frontend.
*/ */
...@@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); 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[]) ...@@ -1397,6 +1377,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
SetProcessingMode(NormalProcessing); 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 * POSTGRES main processing loop begins here
* *
...@@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (sigsetjmp(Warn_restart, 1) != 0) 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) if (DebugLvl >= 1)
elog(DEBUG, "AbortCurrentTransaction"); elog(DEBUG, "AbortCurrentTransaction");
AbortCurrentTransaction(); AbortCurrentTransaction();
InError = false;
if (ExitAfterAbort) if (ExitAfterAbort)
{ {
ProcReleaseLocks(); /* Just to be sure... */ ProcReleaseLocks(); /* Just to be sure... */
proc_exit(0); 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) */ 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[]) ...@@ -1430,7 +1436,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
for (;;) 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 /* XXX this could be moved after ReadCommand below to get more
* sensical behaviour */ * sensical behaviour */
...@@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
* (3) read a command (loop blocks here) * (3) read a command (loop blocks here)
* ---------------- * ----------------
*/ */
set_ps_display("idle");
firstchar = ReadCommand(parser_input); firstchar = ReadCommand(parser_input);
QueryCancel = false; /* forget any earlier CANCEL signal */ QueryCancel = false; /* forget any earlier CANCEL signal */
...@@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
elog(DEBUG, "StartTransactionCommand"); elog(DEBUG, "StartTransactionCommand");
StartTransactionCommand(); StartTransactionCommand();
pg_exec_query(parser_input->data); pg_exec_query_dest(parser_input->data,
whereToSendOutput,
QueryContext);
/* /*
* Invoke IMMEDIATE constraint triggers * Invoke IMMEDIATE constraint triggers
...@@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
* (6) commit the current transaction * (6) commit the current transaction
* *
* Note: if we had an empty input buffer, then we didn't * 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) if (!IsEmptyQuery)
...@@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[]) ...@@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
#ifdef SHOW_MEMORY_STATS #ifdef SHOW_MEMORY_STATS
/* print global-context stats at each commit for leak tracking */ /* print global-context stats at each commit for leak tracking */
if (ShowStats) if (ShowStats)
GlobalMemoryStats(); MemoryContextStats(TopMemoryContext);
#endif #endif
} }
else else
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -22,8 +22,6 @@
#include "utils/ps_status.h" #include "utils/ps_status.h"
static char *CreateOperationTag(int operationType); static char *CreateOperationTag(int operationType);
static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
Node *limcount);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -115,7 +113,7 @@ CreateOperationTag(int operationType) ...@@ -115,7 +113,7 @@ CreateOperationTag(int operationType)
default: default:
elog(DEBUG, "CreateOperationTag: unknown operation type %d", elog(DEBUG, "CreateOperationTag: unknown operation type %d",
operationType); operationType);
tag = NULL; tag = "???";
break; break;
} }
...@@ -123,31 +121,18 @@ CreateOperationTag(int operationType) ...@@ -123,31 +121,18 @@ CreateOperationTag(int operationType)
} }
/* ---------------- /* ----------------
* ProcessPortal * PreparePortal
* ---------------- * ----------------
*/ */
Portal
void PreparePortal(char *portalName)
ProcessPortal(char *portalName,
Query *parseTree,
Plan *plan,
EState *state,
TupleDesc attinfo,
CommandDest dest)
{ {
Portal portal; 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); portal = GetPortalByName(portalName);
if (PortalIsValid(portal)) if (PortalIsValid(portal))
{ {
...@@ -158,70 +143,39 @@ ProcessPortal(char *portalName, ...@@ -158,70 +143,39 @@ ProcessPortal(char *portalName,
} }
/* ---------------- /* ----------------
* Convert the current blank portal into the user-specified * Create the new portal and make its memory context active.
* 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.
* ---------------- * ----------------
*/ */
portal = CreatePortal(portalName);
portal = BlankPortalAssignName(portalName); MemoryContextSwitchTo(PortalGetHeapMemory(portal));
PortalSetQuery(portal,
CreateQueryDesc(parseTree, plan, dest),
attinfo,
state,
PortalCleanup);
/* ---------------- return 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);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ProcessQueryDesc * ProcessQuery
* *
* Read the comments for ProcessQuery() below... * Execute a plan, the non-parallel version
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static void void
ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) ProcessQuery(Query *parsetree,
Plan *plan,
CommandDest dest)
{ {
Query *parseTree; int operation = parsetree->commandType;
Plan *plan; char *tag;
int operation;
char *tag = NULL;
EState *state;
TupleDesc attinfo;
bool isRetrieveIntoPortal; bool isRetrieveIntoPortal;
bool isRetrieveIntoRelation; bool isRetrieveIntoRelation;
Portal portal = NULL;
char *intoName = NULL; char *intoName = NULL;
CommandDest dest; QueryDesc *queryDesc;
EState *state;
/* ---------------- TupleDesc attinfo;
* get info from the query desc
* ----------------
*/
parseTree = queryDesc->parsetree;
plan = queryDesc->plantree;
operation = queryDesc->operation;
set_ps_display(tag = CreateOperationTag(operation)); set_ps_display(tag = CreateOperationTag(operation));
dest = queryDesc->dest;
/* ---------------- /* ----------------
* initialize portal/into relation status * initialize portal/into relation status
...@@ -232,11 +186,11 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) ...@@ -232,11 +186,11 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
if (operation == CMD_SELECT) if (operation == CMD_SELECT)
{ {
if (parseTree->isPortal) if (parsetree->isPortal)
{ {
isRetrieveIntoPortal = true; isRetrieveIntoPortal = true;
intoName = parseTree->into; intoName = parsetree->into;
if (parseTree->isBinary) if (parsetree->isBinary)
{ {
/* /*
...@@ -244,19 +198,38 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) ...@@ -244,19 +198,38 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
* (externalized form) to RemoteInternal (internalized * (externalized form) to RemoteInternal (internalized
* form) * form)
*/ */
dest = queryDesc->dest = RemoteInternal; dest = RemoteInternal;
} }
} }
else if (parseTree->into != NULL) else if (parsetree->into != NULL)
{ {
/* select into table */ /* select into table */
isRetrieveIntoRelation = true; 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 * communication destination during the processing of the
* the query. This only affects the tuple-output function * the query. This only affects the tuple-output function
* - the correct destination will still see BeginCommand() * - the correct destination will still see BeginCommand()
...@@ -293,26 +266,19 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) ...@@ -293,26 +266,19 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
dest); dest);
/* ---------------- /* ----------------
* Named portals do not do a "fetch all" initially, so now * If retrieve into portal, stop now; we do not run the plan
* we return since ExecMain has been called with EXEC_START * until a FETCH command is received.
* 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 (isRetrieveIntoPortal) if (isRetrieveIntoPortal)
{ {
PortalExecutorHeapMemory = NULL; PortalSetQuery(portal,
queryDesc,
attinfo,
state,
PortalCleanup);
ProcessPortal(intoName, MemoryContextSwitchTo(TransactionCommandContext);
parseTree,
plan,
state,
attinfo,
dest);
EndCommand(tag, dest); EndCommand(tag, dest);
return; return;
...@@ -323,14 +289,14 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) ...@@ -323,14 +289,14 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
* actually run the plan.. * actually run the plan..
* ---------------- * ----------------
*/ */
ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount); ExecutorRun(queryDesc, state, EXEC_RUN,
parsetree->limitOffset, parsetree->limitCount);
/* save infos for EndCommand */ /* save infos for EndCommand */
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed); UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
/* ---------------- /* ----------------
* now, we close down all the scans and free allocated resources... * Now, we close down all the scans and free allocated resources.
* with ExecutorEnd()
* ---------------- * ----------------
*/ */
ExecutorEnd(queryDesc, state); ExecutorEnd(queryDesc, state);
...@@ -341,31 +307,3 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) ...@@ -341,31 +307,3 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
*/ */
EndCommand(tag, dest); 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);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -60,10 +60,6 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
static CatCache *Caches = NULL; /* head of list of caches */ 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 * EQPROC is used in CatalogCacheInitializeCache to find the equality
...@@ -135,6 +131,28 @@ cc_hashname(PG_FUNCTION_ARGS) ...@@ -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 * CatalogCacheInitializeCache
* -------------------------------- * --------------------------------
...@@ -183,9 +201,10 @@ CatalogCacheInitializeCache(CatCache * cache, ...@@ -183,9 +201,10 @@ CatalogCacheInitializeCache(CatCache * cache,
* do not vanish at the end of a transaction * do not vanish at the end of a transaction
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* If no relation was passed we must open it to get access to * If no relation was passed we must open it to get access to
...@@ -415,7 +434,7 @@ CatalogCacheComputeTupleHashIndex(CatCache * cacheInOutP, ...@@ -415,7 +434,7 @@ CatalogCacheComputeTupleHashIndex(CatCache * cacheInOutP,
/* -------------------------------- /* --------------------------------
* CatCacheRemoveCTup * CatCacheRemoveCTup
* *
* NB: assumes caller has switched to CacheCxt * NB: assumes caller has switched to CacheMemoryContext
* -------------------------------- * --------------------------------
*/ */
static void static void
...@@ -477,9 +496,10 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */ ...@@ -477,9 +496,10 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */
* switch to the cache context for our memory allocations * switch to the cache context for our memory allocations
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* inspect every cache that could contain the tuple * inspect every cache that could contain the tuple
...@@ -552,10 +572,10 @@ ResetSystemCache() ...@@ -552,10 +572,10 @@ ResetSystemCache()
* do not vanish at the end of a transaction * do not vanish at the end of a transaction
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* here we purge the contents of all the caches * here we purge the contents of all the caches
...@@ -681,10 +701,10 @@ InitSysCache(char *relname, ...@@ -681,10 +701,10 @@ InitSysCache(char *relname,
* do not vanish at the end of a transaction * do not vanish at the end of a transaction
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* allocate a new cache structure * allocate a new cache structure
...@@ -839,14 +859,14 @@ SearchSelfReferences(CatCache * cache) ...@@ -839,14 +859,14 @@ SearchSelfReferences(CatCache * cache)
HeapScanDesc sd; HeapScanDesc sd;
MemoryContext oldcxt; MemoryContext oldcxt;
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
rel = heap_open(cache->relationId, AccessShareLock); rel = heap_open(cache->relationId, AccessShareLock);
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey); sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
ntp = heap_getnext(sd, 0); ntp = heap_getnext(sd, 0);
if (!HeapTupleIsValid(ntp)) if (!HeapTupleIsValid(ntp))
elog(ERROR, "SearchSelfReferences: tuple not found"); elog(ERROR, "SearchSelfReferences: tuple not found");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
indexSelfTuple = heap_copytuple(ntp); indexSelfTuple = heap_copytuple(ntp);
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
heap_endscan(sd); heap_endscan(sd);
...@@ -868,14 +888,14 @@ SearchSelfReferences(CatCache * cache) ...@@ -868,14 +888,14 @@ SearchSelfReferences(CatCache * cache)
HeapScanDesc sd; HeapScanDesc sd;
MemoryContext oldcxt; MemoryContext oldcxt;
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
rel = heap_open(cache->relationId, AccessShareLock); rel = heap_open(cache->relationId, AccessShareLock);
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey); sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
ntp = heap_getnext(sd, 0); ntp = heap_getnext(sd, 0);
if (!HeapTupleIsValid(ntp)) if (!HeapTupleIsValid(ntp))
elog(ERROR, "SearchSelfReferences: tuple not found"); elog(ERROR, "SearchSelfReferences: tuple not found");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp); operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
heap_endscan(sd); heap_endscan(sd);
...@@ -908,7 +928,6 @@ SearchSysCache(CatCache * cache, ...@@ -908,7 +928,6 @@ SearchSysCache(CatCache * cache,
CatCTup *nct2; CatCTup *nct2;
Dlelem *elt; Dlelem *elt;
HeapTuple ntp = NULL; HeapTuple ntp = NULL;
Relation relation; Relation relation;
MemoryContext oldcxt; MemoryContext oldcxt;
...@@ -1020,10 +1039,10 @@ SearchSysCache(CatCache * cache, ...@@ -1020,10 +1039,10 @@ SearchSysCache(CatCache * cache,
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* Scan the relation to find the tuple. If there's an index, and * Scan the relation to find the tuple. If there's an index, and
...@@ -1060,12 +1079,13 @@ SearchSysCache(CatCache * cache, ...@@ -1060,12 +1079,13 @@ SearchSysCache(CatCache * cache,
*/ */
if (HeapTupleIsValid(indextp)) if (HeapTupleIsValid(indextp))
{ {
MemoryContextSwitchTo((MemoryContext) CacheCxt); MemoryContextSwitchTo(CacheMemoryContext);
ntp = heap_copytuple(indextp); ntp = heap_copytuple(indextp);
/* this switch is probably not needed anymore: */
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
heap_freetuple(indextp); heap_freetuple(indextp);
} }
MemoryContextSwitchTo((MemoryContext) CacheCxt); MemoryContextSwitchTo(CacheMemoryContext);
} }
else else
{ {
...@@ -1084,7 +1104,7 @@ SearchSysCache(CatCache * cache, ...@@ -1084,7 +1104,7 @@ SearchSysCache(CatCache * cache,
ntp = heap_getnext(sd, 0); ntp = heap_getnext(sd, 0);
MemoryContextSwitchTo((MemoryContext) CacheCxt); MemoryContextSwitchTo(CacheMemoryContext);
if (HeapTupleIsValid(ntp)) if (HeapTupleIsValid(ntp))
{ {
...@@ -1097,7 +1117,7 @@ SearchSysCache(CatCache * cache, ...@@ -1097,7 +1117,7 @@ SearchSysCache(CatCache * cache,
heap_endscan(sd); heap_endscan(sd);
MemoryContextSwitchTo((MemoryContext) CacheCxt); MemoryContextSwitchTo(CacheMemoryContext);
} }
cache->busy = false; cache->busy = false;
...@@ -1205,9 +1225,10 @@ RelationInvalidateCatalogCacheTuple(Relation relation, ...@@ -1205,9 +1225,10 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
* switch to the cache memory context * switch to the cache memory context
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* for each cache * for each cache
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -917,10 +917,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
/* ---------------- /* ----------------
* allocate storage for the relation descriptor, * allocate storage for the relation descriptor,
* initialize relation->rd_rel and get the access method id. * 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); relation = AllocateRelationDesc(oldrelation, natts, relp);
relam = relation->rd_rel->relam; relam = relation->rd_rel->relam;
...@@ -1383,7 +1383,7 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1383,7 +1383,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
if (relation->rd_isnailed) if (relation->rd_isnailed)
return; return;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* /*
* Remove relation from hash tables * Remove relation from hash tables
...@@ -1574,7 +1574,7 @@ RelationForgetRelation(Oid rid) ...@@ -1574,7 +1574,7 @@ RelationForgetRelation(Oid rid)
List *curr; List *curr;
List *prev = NIL; List *prev = NIL;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
foreach(curr, newlyCreatedRelns) foreach(curr, newlyCreatedRelns)
{ {
...@@ -1731,10 +1731,7 @@ RelationRegisterRelation(Relation relation) ...@@ -1731,10 +1731,7 @@ RelationRegisterRelation(Relation relation)
{ {
MemoryContext oldcxt; MemoryContext oldcxt;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
if (oldcxt != (MemoryContext) CacheCxt)
elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
RelationInitLockInfo(relation); RelationInitLockInfo(relation);
...@@ -1769,7 +1766,7 @@ RelationPurgeLocalRelation(bool xactCommitted) ...@@ -1769,7 +1766,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
if (newlyCreatedRelns == NULL) if (newlyCreatedRelns == NULL)
return; return;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
while (newlyCreatedRelns) while (newlyCreatedRelns)
{ {
...@@ -1822,10 +1819,10 @@ RelationInitialize(void) ...@@ -1822,10 +1819,10 @@ RelationInitialize(void)
* switch to cache memory context * switch to cache memory context
* ---------------- * ----------------
*/ */
if (!CacheCxt) if (!CacheMemoryContext)
CacheCxt = CreateGlobalMemory("Cache"); CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ---------------- /* ----------------
* create global caches * create global caches
...@@ -2186,7 +2183,7 @@ RelationGetIndexList(Relation relation) ...@@ -2186,7 +2183,7 @@ RelationGetIndexList(Relation relation)
heap_close(indrel, AccessShareLock); heap_close(indrel, AccessShareLock);
/* Now save a copy of the completed list in the relcache entry. */ /* 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_indexlist = listCopy(result);
relation->rd_indexfound = true; relation->rd_indexfound = true;
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -67,7 +67,7 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
MemoryContext oldcxt; MemoryContext oldcxt;
TempTable *temp_rel; TempTable *temp_rel;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
temp_rel = (TempTable *) palloc(sizeof(TempTable)); temp_rel = (TempTable *) palloc(sizeof(TempTable));
temp_rel->user_relname = (char *) palloc(NAMEDATALEN); temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
...@@ -135,7 +135,7 @@ remove_temp_relation(Oid relid) ...@@ -135,7 +135,7 @@ remove_temp_relation(Oid relid)
List *l, List *l,
*prev; *prev;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
prev = NIL; prev = NIL;
l = temp_rels; l = temp_rels;
...@@ -185,7 +185,7 @@ invalidate_temp_relations(void) ...@@ -185,7 +185,7 @@ invalidate_temp_relations(void)
List *l, List *l,
*prev; *prev;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
prev = NIL; prev = NIL;
l = temp_rels; l = temp_rels;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -27,7 +27,7 @@
#include <sys/time.h> #include <sys/time.h>
#include <ctype.h> #include <ctype.h>
#ifdef ENABLE_SYSLOG #ifdef ENABLE_SYSLOG
# include <syslog.h> #include <syslog.h>
#endif #endif
#include "libpq/libpq.h" #include "libpq/libpq.h"
...@@ -89,10 +89,9 @@ static int ElogDebugIndentLevel = 0; ...@@ -89,10 +89,9 @@ static int ElogDebugIndentLevel = 0;
*-------------------- *--------------------
*/ */
void void
elog(int lev, const char *fmt,...) elog(int lev, const char *fmt, ...)
{ {
va_list ap; va_list ap;
/* /*
* The expanded format and final output message are dynamically * The expanded format and final output message are dynamically
* allocated if necessary, but not if they fit in the "reasonable * allocated if necessary, but not if they fit in the "reasonable
...@@ -101,12 +100,21 @@ elog(int lev, const char *fmt,...) ...@@ -101,12 +100,21 @@ elog(int lev, const char *fmt,...)
* working (since memory-clobber errors often take out malloc first). * working (since memory-clobber errors often take out malloc first).
* Don't make these buffers unreasonably large though, on pain of * Don't make these buffers unreasonably large though, on pain of
* having to chase a bug with no error message. * 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 fmt_fixedbuf[128];
char msg_fixedbuf[256]; char msg_fixedbuf[256];
char *fmt_buf = fmt_fixedbuf; char *fmt_buf = fmt_fixedbuf;
char *msg_buf = msg_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: */ /* this buffer is only used if errno has a bogus value: */
char errorstr_buf[32]; char errorstr_buf[32];
const char *errorstr; const char *errorstr;
...@@ -115,7 +123,6 @@ elog(int lev, const char *fmt,...) ...@@ -115,7 +123,6 @@ elog(int lev, const char *fmt,...)
char *bp; char *bp;
int indent = 0; int indent = 0;
int space_needed; int space_needed;
int len; int len;
/* size of the prefix needed for timestamp and pid, if enabled */ /* size of the prefix needed for timestamp and pid, if enabled */
size_t timestamp_size; size_t timestamp_size;
...@@ -123,6 +130,15 @@ elog(int lev, const char *fmt,...) ...@@ -123,6 +130,15 @@ elog(int lev, const char *fmt,...)
if (lev <= DEBUG && Debugfile < 0) if (lev <= DEBUG && Debugfile < 0)
return; /* ignore debug msgs if noplace to send */ 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) if (lev == ERROR || lev == FATAL)
{ {
/* this is probably redundant... */ /* this is probably redundant... */
...@@ -156,21 +172,11 @@ elog(int lev, const char *fmt,...) ...@@ -156,21 +172,11 @@ elog(int lev, const char *fmt,...)
prefix = "ERROR: "; prefix = "ERROR: ";
break; break;
default: default:
/* temporarily use msg buf for prefix */ sprintf(prefix_buf, "FATAL %d: ", lev);
sprintf(msg_fixedbuf, "FATAL %d: ", lev); prefix = prefix_buf;
prefix = msg_fixedbuf;
break; 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; timestamp_size = 0;
if (Log_timestamp) if (Log_timestamp)
timestamp_size += TIMESTAMP_SIZE; timestamp_size += TIMESTAMP_SIZE;
...@@ -190,9 +196,13 @@ elog(int lev, const char *fmt,...) ...@@ -190,9 +196,13 @@ elog(int lev, const char *fmt,...)
fmt_buf = (char *) malloc(space_needed); fmt_buf = (char *) malloc(space_needed);
if (fmt_buf == NULL) 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; fmt_buf = fmt_fixedbuf;
lev = REALLYFATAL; if (lev < FATAL)
{
lev = ERROR;
prefix = "ERROR: ";
}
fmt = "elog: out of memory"; /* this must fit in fmt = "elog: out of memory"; /* this must fit in
* fmt_fixedbuf! */ * fmt_fixedbuf! */
} }
...@@ -281,15 +291,20 @@ elog(int lev, const char *fmt,...) ...@@ -281,15 +291,20 @@ elog(int lev, const char *fmt,...)
msg_buf = (char *) malloc(space_needed); msg_buf = (char *) malloc(space_needed);
if (msg_buf == NULL) 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; msg_buf = msg_fixedbuf;
lev = REALLYFATAL; if (lev < FATAL)
{
lev = ERROR;
prefix = "ERROR: ";
}
msg_buf[0] = '\0'; msg_buf[0] = '\0';
if (Log_timestamp) if (Log_timestamp)
strcat(msg_buf, print_timestamp()); strcat(msg_buf, print_timestamp());
if (Log_pid) if (Log_pid)
strcat(msg_buf, print_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; break;
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -134,7 +134,7 @@ load_external_function(char *filename, char *funcname)
file_scanner = (DynamicFileList *) file_scanner = (DynamicFileList *)
malloc(sizeof(DynamicFileList) + strlen(filename)); malloc(sizeof(DynamicFileList) + strlen(filename));
if (file_scanner == NULL) 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)); MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
strcpy(file_scanner->filename, filename); strcpy(file_scanner->filename, filename);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -56,8 +56,7 @@
/* /*
* Private function prototypes * Private function prototypes
*/ */
static long *DynaHashAlloc(unsigned int size); static void *DynaHashAlloc(Size size);
static void DynaHashFree(Pointer ptr);
static uint32 call_hash(HTAB *hashp, char *k); static uint32 call_hash(HTAB *hashp, char *k);
static SEG_OFFSET seg_alloc(HTAB *hashp); static SEG_OFFSET seg_alloc(HTAB *hashp);
static int bucket_alloc(HTAB *hashp); static int bucket_alloc(HTAB *hashp);
...@@ -66,9 +65,7 @@ static int expand_table(HTAB *hashp); ...@@ -66,9 +65,7 @@ static int expand_table(HTAB *hashp);
static int hdefault(HTAB *hashp); static int hdefault(HTAB *hashp);
static int init_htab(HTAB *hashp, int nelem); static int init_htab(HTAB *hashp, int nelem);
typedef long *((*dhalloc_ptr) ());
#ifndef FRONTEND
/* ---------------- /* ----------------
* memory allocation routines * memory allocation routines
* *
...@@ -84,34 +81,24 @@ typedef long *((*dhalloc_ptr) ()); ...@@ -84,34 +81,24 @@ typedef long *((*dhalloc_ptr) ());
* do the latter -cim 1/19/91 * do the latter -cim 1/19/91
* ---------------- * ----------------
*/ */
GlobalMemory DynaHashCxt = (GlobalMemory) NULL; static MemoryContext DynaHashCxt = NULL;
static long * static void *
DynaHashAlloc(unsigned int size) DynaHashAlloc(Size size)
{ {
if (!DynaHashCxt) if (!DynaHashCxt)
DynaHashCxt = CreateGlobalMemory("DynaHash"); DynaHashCxt = AllocSetContextCreate(TopMemoryContext,
"DynaHash",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
return (long *) return MemoryContextAlloc(DynaHashCxt, size);
MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
}
static void
DynaHashFree(Pointer ptr)
{
MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
} }
#define MEM_ALLOC DynaHashAlloc #define MEM_ALLOC DynaHashAlloc
#define MEM_FREE DynaHashFree
#else /* FRONTEND */
#define MEM_ALLOC palloc
#define MEM_FREE pfree #define MEM_FREE pfree
#endif /* FRONTEND */
/* /*
* pointer access macros. Shared memory implementation cannot * pointer access macros. Shared memory implementation cannot
...@@ -147,7 +134,7 @@ hash_create(int nelem, HASHCTL *info, int flags) ...@@ -147,7 +134,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
HTAB *hashp; HTAB *hashp;
hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB)); hashp = (HTAB *) MEM_ALLOC(sizeof(HTAB));
MemSet(hashp, 0, sizeof(HTAB)); MemSet(hashp, 0, sizeof(HTAB));
if (flags & HASH_FUNCTION) if (flags & HASH_FUNCTION)
...@@ -181,7 +168,7 @@ hash_create(int nelem, HASHCTL *info, int flags) ...@@ -181,7 +168,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
/* setup hash table defaults */ /* setup hash table defaults */
hashp->hctl = NULL; hashp->hctl = NULL;
hashp->alloc = (dhalloc_ptr) MEM_ALLOC; hashp->alloc = MEM_ALLOC;
hashp->dir = NULL; hashp->dir = NULL;
hashp->segbase = NULL; hashp->segbase = NULL;
...@@ -189,7 +176,7 @@ hash_create(int nelem, HASHCTL *info, int flags) ...@@ -189,7 +176,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
if (!hashp->hctl) if (!hashp->hctl)
{ {
hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR)); hashp->hctl = (HHDR *) hashp->alloc(sizeof(HHDR));
if (!hashp->hctl) if (!hashp->hctl)
return 0; return 0;
} }
...@@ -318,7 +305,8 @@ init_htab(HTAB *hashp, int nelem) ...@@ -318,7 +305,8 @@ init_htab(HTAB *hashp, int nelem)
/* Allocate a directory */ /* Allocate a directory */
if (!(hashp->dir)) 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) if (!hashp->dir)
return -1; return -1;
} }
...@@ -445,7 +433,7 @@ hash_destroy(HTAB *hashp) ...@@ -445,7 +433,7 @@ hash_destroy(HTAB *hashp)
/* cannot destroy a shared memory hash table */ /* cannot destroy a shared memory hash table */
Assert(!hashp->segbase); Assert(!hashp->segbase);
/* allocation method must be one we know how to free, too */ /* 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); hash_stats("destroy", hashp);
...@@ -885,7 +873,7 @@ dir_realloc(HTAB *hashp) ...@@ -885,7 +873,7 @@ dir_realloc(HTAB *hashp)
new_dirsize = new_dsize * sizeof(SEG_OFFSET); new_dirsize = new_dsize * sizeof(SEG_OFFSET);
old_p = (char *) hashp->dir; old_p = (char *) hashp->dir;
p = (char *) hashp->alloc((unsigned long) new_dirsize); p = (char *) hashp->alloc((Size) new_dirsize);
if (p != NULL) if (p != NULL)
{ {
...@@ -906,8 +894,7 @@ seg_alloc(HTAB *hashp) ...@@ -906,8 +894,7 @@ seg_alloc(HTAB *hashp)
SEGMENT segp; SEGMENT segp;
SEG_OFFSET segOffset; SEG_OFFSET segOffset;
segp = (SEGMENT) hashp->alloc((unsigned long) segp = (SEGMENT) hashp->alloc(sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
if (!segp) if (!segp)
return 0; return 0;
...@@ -937,8 +924,7 @@ bucket_alloc(HTAB *hashp) ...@@ -937,8 +924,7 @@ bucket_alloc(HTAB *hashp)
/* make sure its aligned correctly */ /* make sure its aligned correctly */
bucketSize = MAXALIGN(bucketSize); bucketSize = MAXALIGN(bucketSize);
tmpBucket = (ELEMENT *) tmpBucket = (ELEMENT *) hashp->alloc(BUCKET_ALLOC_INCR * bucketSize);
hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
if (!tmpBucket) if (!tmpBucket)
return 0; return 0;
......
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
# Makefile for utils/init # Makefile for utils/init
# #
# IDENTIFICATION # 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 = ../../.. SRCDIR = ../../..
include ../../../Makefile.global 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 all: SUBSYS.o
...@@ -27,4 +27,3 @@ clean: ...@@ -27,4 +27,3 @@ clean:
ifeq (depend,$(wildcard depend)) ifeq (depend,$(wildcard depend))
include depend include depend
endif endif
/*-------------------------------------------------------------------------
*
* 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);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -40,8 +40,6 @@
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#endif #endif
void BaseInit(void);
static void ReverifyMyDatabase(const char *name); static void ReverifyMyDatabase(const char *name);
static void InitCommunication(void); static void InitCommunication(void);
...@@ -222,8 +220,6 @@ InitCommunication() ...@@ -222,8 +220,6 @@ InitCommunication()
* Be very careful with the order of calls in the InitPostgres function. * Be very careful with the order of calls in the InitPostgres function.
* -------------------------------- * --------------------------------
*/ */
extern int NBuffers;
int lockingOff = 0; /* backend -L switch */ int lockingOff = 0; /* backend -L switch */
/* /*
...@@ -405,21 +401,6 @@ InitPostgres(const char *dbname) ...@@ -405,21 +401,6 @@ InitPostgres(const char *dbname)
void void
BaseInit(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 * Attach to shared memory and semaphores, and initialize our
* input/output/debugging file descriptors. * input/output/debugging file descriptors.
...@@ -427,4 +408,6 @@ BaseInit(void) ...@@ -427,4 +408,6 @@ BaseInit(void)
InitCommunication(); InitCommunication();
DebugFileOpen(); DebugFileOpen();
smgrinit(); smgrinit();
EnablePortalManager(); /* memory for portal/transaction stuff */
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* WIN1250 client encoding support contributed by Pavel Behal * WIN1250 client encoding support contributed by Pavel Behal
* SJIS UDC (NEC selection IBM kanji) support contributed by Eiji Tokuya * 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[] = { ...@@ -1521,7 +1521,8 @@ pg_encoding_conv_tbl pg_conv_tbl[] = {
}; };
#ifdef DEBUGMAIN #ifdef DEBUGMAIN
#include "utils/mcxt.h" #include "postgres.h"
#include "utils/memutils.h"
/* /*
* testing for sjis2mic() and mic2sjis() * testing for sjis2mic() and mic2sjis()
*/ */
...@@ -1565,21 +1566,23 @@ main() ...@@ -1565,21 +1566,23 @@ main()
void void
elog(int lev, const char *fmt,...) elog(int lev, const char *fmt,...)
{ {
}; }
MemoryContext CurrentMemoryContext; MemoryContext CurrentMemoryContext;
Pointer
void *
MemoryContextAlloc(MemoryContext context, Size size) MemoryContextAlloc(MemoryContext context, Size size)
{ {
}; }
Pointer
MemoryContextRealloc(MemoryContext context,
Pointer pointer,
Size size)
{
};
void void
MemoryContextFree(MemoryContext context, Pointer pointer) pfree(void *pointer)
{ {
}; }
void *
repalloc(void *pointer, Size size)
{
}
#endif #endif
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
# Makefile for utils/mmgr # Makefile for utils/mmgr
# #
# IDENTIFICATION # 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 = ../../.. SRCDIR = ../../..
include ../../../Makefile.global include ../../../Makefile.global
OBJS = aset.o mcxt.o palloc.o portalmem.o oset.o OBJS = aset.o mcxt.o portalmem.o
all: SUBSYS.o all: SUBSYS.o
......
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.
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
* aset.c * aset.c
* Allocation set definitions. * Allocation set definitions.
* *
* AllocSet is our standard implementation of the abstract MemoryContext
* type.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
*
* IDENTIFICATION * 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: * NOTE:
* This is a new (Feb. 05, 1999) implementation of the allocation set * This is a new (Feb. 05, 1999) implementation of the allocation set
...@@ -30,15 +33,68 @@ ...@@ -30,15 +33,68 @@
* AllocSetReset() under the old way. * AllocSetReset() under the old way.
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#undef AllocSetReset /*
#undef malloc * AllocSetContext is defined in nodes/memnodes.h.
#undef free */
#undef realloc 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), * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
...@@ -59,9 +115,9 @@ ...@@ -59,9 +115,9 @@
/* Size of largest chunk that we use a fixed size for */ /* 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 * 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(). * the bookkeeping load on malloc().
* *
* Blocks allocated to hold oversize chunks do not follow this rule, however; * Blocks allocated to hold oversize chunks do not follow this rule, however;
...@@ -74,20 +130,21 @@ ...@@ -74,20 +130,21 @@
* AllocSetAlloc has discretion whether to put the request into an existing * AllocSetAlloc has discretion whether to put the request into an existing
* block or make a single-chunk block. * 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. * 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) #define ALLOC_BIGCHUNK_LIMIT (64 * 1024)
/* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */ /* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData)) #define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData)) #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) \ #define AllocPointerGetChunk(ptr) \
((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ)) ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
#define AllocChunkGetPointer(chk) \ #define AllocChunkGetPointer(chk) \
...@@ -95,6 +152,29 @@ ...@@ -95,6 +152,29 @@
#define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset)) #define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
#define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size) #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) ...@@ -127,92 +207,182 @@ AllocSetFreeIndex(Size size)
* Public routines * Public routines
*/ */
/* /*
* AllocSetInit * AllocSetContextCreate
* Initializes given allocation set. * Create a new AllocSet context.
*
* Note:
* The semantics of the mode are explained above. Limit is ignored
* for dynamic and static modes.
* *
* Exceptions: * parent: parent context, or NULL if top-level context
* BadArg if set is invalid pointer. * name: name of context (for debugging --- string will be copied)
* BadArg if mode is invalid. * minContextSize: minimum context size
* initBlockSize: initial allocation block size
* maxBlockSize: maximum allocation block size
*/ */
void MemoryContext
AllocSetInit(AllocSet set, AllocMode mode, Size limit) AllocSetContextCreate(MemoryContext parent,
const char *name,
Size minContextSize,
Size initBlockSize,
Size maxBlockSize)
{ {
AssertArg(PointerIsValid(set)); AllocSet context;
AssertArg((int) DynamicAllocMode <= (int) mode);
AssertArg((int) mode <= (int) BoundedAllocMode); /* 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 * Grab always-allocated space, if requested
* limit is also ignored. This affects this whole file.
*/ */
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 * AllocSetReset
* Frees all memory which is allocated in the given set. * Frees all memory which is allocated in the given set.
* *
* Exceptions: * Actually, this routine has some discretion about what to do.
* BadArg if set is invalid. * 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 static void
AllocSetReset(AllocSet set) AllocSetReset(MemoryContext context)
{ {
AllocSet set = (AllocSet) context;
AllocBlock block = set->blocks; AllocBlock block = set->blocks;
AllocBlock next;
AssertArg(AllocSetIsValid(set)); AssertArg(AllocSetIsValid(set));
while (block != NULL) 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 #ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */ /* Wipe freed memory for debugging purposes */
memset(block, 0x7F, ((char *) block->endptr) - ((char *) block)); memset(block->freeptr, 0x7F,
((char *) block->endptr) - ((char *) block->freeptr));
#endif #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; 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 * AllocSetDelete
* True iff allocation set contains given allocation element. * Frees all memory which is allocated in the given set,
* in preparation for deletion of the set.
* *
* Exceptions: * Unlike AllocSetReset, this *must* free all resources of the set.
* BadArg if set is invalid. * But note we are not responsible for deleting the context node itself.
* BadArg if pointer is invalid.
*/ */
bool static void
AllocSetContains(AllocSet set, AllocPointer pointer) AllocSetDelete(MemoryContext context)
{ {
AllocSet set = (AllocSet) context;
AllocBlock block = set->blocks;
AssertArg(AllocSetIsValid(set)); 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 * AllocSetAlloc
* Returns pointer to allocated memory of given size; memory is added * Returns pointer to allocated memory of given size; memory is added
* to the set. * to the set.
*
* Exceptions:
* BadArg if set is invalid.
* MemoryExhausted if allocation fails.
*/ */
AllocPointer static void *
AllocSetAlloc(AllocSet set, Size size) AllocSetAlloc(MemoryContext context, Size size)
{ {
AllocSet set = (AllocSet) context;
AllocBlock block; AllocBlock block;
AllocChunk chunk; AllocChunk chunk;
AllocChunk priorfree = NULL; AllocChunk priorfree = NULL;
...@@ -225,7 +395,6 @@ AllocSetAlloc(AllocSet set, Size size) ...@@ -225,7 +395,6 @@ AllocSetAlloc(AllocSet set, Size size)
/* /*
* Lookup in the corresponding free list if there is a free chunk we * Lookup in the corresponding free list if there is a free chunk we
* could reuse * could reuse
*
*/ */
fidx = AllocSetFreeIndex(size); fidx = AllocSetFreeIndex(size);
for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset) for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
...@@ -238,7 +407,6 @@ AllocSetAlloc(AllocSet set, Size size) ...@@ -238,7 +407,6 @@ AllocSetAlloc(AllocSet set, Size size)
/* /*
* If one is found, remove it from the free list, make it again a * If one is found, remove it from the free list, make it again a
* member of the alloc set and return its data address. * member of the alloc set and return its data address.
*
*/ */
if (chunk != NULL) if (chunk != NULL)
{ {
...@@ -284,7 +452,7 @@ AllocSetAlloc(AllocSet set, Size size) ...@@ -284,7 +452,7 @@ AllocSetAlloc(AllocSet set, Size size)
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
block = (AllocBlock) malloc(blksize); block = (AllocBlock) malloc(blksize);
if (block == NULL) if (block == NULL)
elog(FATAL, "Memory exhausted in AllocSetAlloc()"); elog(ERROR, "Memory exhausted in AllocSetAlloc()");
block->aset = set; block->aset = set;
block->freeptr = block->endptr = ((char *) block) + blksize; block->freeptr = block->endptr = ((char *) block) + blksize;
...@@ -317,7 +485,7 @@ AllocSetAlloc(AllocSet set, Size size) ...@@ -317,7 +485,7 @@ AllocSetAlloc(AllocSet set, Size size)
{ {
if (set->blocks == NULL) if (set->blocks == NULL)
{ {
blksize = ALLOC_MIN_BLOCK_SIZE; blksize = set->initBlockSize;
block = (AllocBlock) malloc(blksize); block = (AllocBlock) malloc(blksize);
} }
else else
...@@ -327,15 +495,18 @@ AllocSetAlloc(AllocSet set, Size size) ...@@ -327,15 +495,18 @@ AllocSetAlloc(AllocSet set, Size size)
/* /*
* Special case: if very first allocation was for a large * Special case: if very first allocation was for a large
* chunk, could have a funny-sized top block. Do something * chunk (or we have a small "keeper" block), could have an
* reasonable. * undersized top block. Do something reasonable.
*/ */
if (blksize < ALLOC_MIN_BLOCK_SIZE) if (blksize < set->initBlockSize)
blksize = ALLOC_MIN_BLOCK_SIZE; blksize = set->initBlockSize;
/* Crank it up, but not past max */ else
blksize <<= 1; {
if (blksize > ALLOC_MAX_BLOCK_SIZE) /* Crank it up, but not past max */
blksize = ALLOC_MAX_BLOCK_SIZE; blksize <<= 1;
if (blksize > set->maxBlockSize)
blksize = set->maxBlockSize;
}
/* Try to allocate it */ /* Try to allocate it */
block = (AllocBlock) malloc(blksize); block = (AllocBlock) malloc(blksize);
...@@ -352,7 +523,7 @@ AllocSetAlloc(AllocSet set, Size size) ...@@ -352,7 +523,7 @@ AllocSetAlloc(AllocSet set, Size size)
} }
if (block == NULL) if (block == NULL)
elog(FATAL, "Memory exhausted in AllocSetAlloc()"); elog(ERROR, "Memory exhausted in AllocSetAlloc()");
block->aset = set; block->aset = set;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ; block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize; block->endptr = ((char *) block) + blksize;
...@@ -376,22 +547,12 @@ AllocSetAlloc(AllocSet set, Size size) ...@@ -376,22 +547,12 @@ AllocSetAlloc(AllocSet set, Size size)
/* /*
* AllocSetFree * AllocSetFree
* Frees allocated memory; memory is removed from the set. * 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 static void
AllocSetFree(AllocSet set, AllocPointer pointer) AllocSetFree(MemoryContext context, void *pointer)
{ {
AllocChunk chunk; AllocSet set = (AllocSet) context;
AllocChunk chunk = AllocPointerGetChunk(pointer);
/* AssertArg(AllocSetIsValid(set)); */
/* AssertArg(AllocPointerIsValid(pointer)); */
AssertArg(AllocSetContains(set, pointer));
chunk = AllocPointerGetChunk(pointer);
#ifdef CLOBBER_FREED_MEMORY #ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */ /* Wipe freed memory for debugging purposes */
...@@ -446,24 +607,15 @@ AllocSetFree(AllocSet set, AllocPointer pointer) ...@@ -446,24 +607,15 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
* Returns new pointer to allocated memory of given size; this memory * Returns new pointer to allocated memory of given size; this memory
* is added to the set. Memory associated with given pointer is copied * is added to the set. Memory associated with given pointer is copied
* into the new memory, and the old memory is freed. * 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 static void *
AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size) AllocSetRealloc(MemoryContext context, void *pointer, Size size)
{ {
AllocSet set = (AllocSet) context;
Size oldsize; 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 * allocated area already is >= the new size. (In particular, we
* always fall out here if the requested size is a decrease.) * always fall out here if the requested size is a decrease.)
*/ */
...@@ -503,7 +655,7 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size) ...@@ -503,7 +655,7 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
block = (AllocBlock) realloc(block, blksize); block = (AllocBlock) realloc(block, blksize);
if (block == NULL) if (block == NULL)
elog(FATAL, "Memory exhausted in AllocSetReAlloc()"); elog(ERROR, "Memory exhausted in AllocSetReAlloc()");
block->freeptr = block->endptr = ((char *) block) + blksize; block->freeptr = block->endptr = ((char *) block) + blksize;
/* Update pointers since block has likely been moved */ /* Update pointers since block has likely been moved */
...@@ -520,35 +672,26 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size) ...@@ -520,35 +672,26 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
/* Normal small-chunk case: just do it by brute force. */ /* Normal small-chunk case: just do it by brute force. */
/* allocate new chunk */ /* allocate new chunk */
AllocPointer newPointer = AllocSetAlloc(set, size); AllocPointer newPointer = AllocSetAlloc((MemoryContext) set, size);
/* transfer existing data (certain to fit) */ /* transfer existing data (certain to fit) */
memcpy(newPointer, pointer, oldsize); memcpy(newPointer, pointer, oldsize);
/* free old chunk */ /* free old chunk */
AllocSetFree(set, pointer); AllocSetFree((MemoryContext) set, pointer);
return newPointer; return newPointer;
} }
} }
/*
* AllocSetDump
* Displays allocated set.
*/
void
AllocSetDump(AllocSet set)
{
elog(DEBUG, "Currently unable to dump AllocSet");
}
/* /*
* AllocSetStats * AllocSetStats
* Displays stats about memory consumption of an allocset. * Displays stats about memory consumption of an allocset.
*/ */
void static void
AllocSetStats(AllocSet set, const char *ident) AllocSetStats(MemoryContext context)
{ {
AllocSet set = (AllocSet) context;
long nblocks = 0; long nblocks = 0;
long nchunks = 0; long nchunks = 0;
long totalspace = 0; long totalspace = 0;
...@@ -557,8 +700,6 @@ AllocSetStats(AllocSet set, const char *ident) ...@@ -557,8 +700,6 @@ AllocSetStats(AllocSet set, const char *ident)
AllocChunk chunk; AllocChunk chunk;
int fidx; int fidx;
AssertArg(AllocSetIsValid(set));
for (block = set->blocks; block != NULL; block = block->next) for (block = set->blocks; block != NULL; block = block->next)
{ {
nblocks++; nblocks++;
...@@ -576,6 +717,6 @@ AllocSetStats(AllocSet set, const char *ident) ...@@ -576,6 +717,6 @@ AllocSetStats(AllocSet set, const char *ident)
} }
fprintf(stderr, fprintf(stderr,
"%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n", "%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); totalspace - freespace);
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* mcxt.c * 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) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -17,41 +23,8 @@
#include "nodes/memnodes.h" #include "nodes/memnodes.h"
#include "utils/excid.h" #include "utils/excid.h"
#include "utils/module.h" #include "utils/memutils.h"
#undef MemoryContextAlloc
#undef MemoryContextFree
#undef malloc
#undef free
/*
* Global State
*/
static int MemoryContextEnableCount = 0;
#define MemoryContextEnabled (MemoryContextEnableCount > 0)
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 * * GLOBAL MEMORY *
...@@ -59,478 +32,451 @@ static OrderedSetData ActiveGlobalMemorySetData; /* uninitialized */ ...@@ -59,478 +32,451 @@ static OrderedSetData ActiveGlobalMemorySetData; /* uninitialized */
/* /*
* CurrentMemoryContext * CurrentMemoryContext
* Memory context for general global allocations. * Default memory context for allocations.
*/ */
DLLIMPORT MemoryContext CurrentMemoryContext = NULL; 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: * EXPORTED ROUTINES *
* TopGlobalMemory is handled specially because of bootstrapping. *****************************************************************************/
*/
/* extern bool EqualGlobalMemory(); */
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 * MemoryContextInit
* Memory context for general global allocations. * Start up the memory-context subsystem.
* *
* Note: * This must be called before creating contexts or allocating memory in
* Don't use this memory context for random allocations. If you * contexts. TopMemoryContext and ErrorContext are initialized here;
* allocate something here, you are expected to clean it up when * other contexts must be created afterwards.
* appropriate.
*/
MemoryContext TopMemoryContext = (MemoryContext) &TopGlobalMemoryData;
/*
* Module State
*/
/*
* EnableMemoryContext
* Enables/disables memory management and global contexts.
* *
* Note: * In normal multi-backend operation, this is called once during
* This must be called before creating contexts or allocating memory. * postmaster startup, and not at all by individual backend startup
* This must be called before other contexts are created. * (since the backends inherit an already-initialized context subsystem
* by virtue of being forked off the postmaster).
* *
* Exceptions: * In a standalone backend this must be called during backend startup.
* BadArg if on is invalid.
* BadState if on is false when disabled.
*/ */
void void
EnableMemoryContext(bool on) MemoryContextInit(void)
{ {
static bool processing = false; AssertState(TopMemoryContext == NULL);
/*
AssertState(!processing); * Initialize TopMemoryContext as an AllocSetContext with slow
AssertArg(BoolIsValid(on)); * growth rate --- we don't really expect much to be allocated in it.
*
if (BypassEnable(&MemoryContextEnableCount, on)) * (There is special-case code in MemoryContextCreate() for this call.)
return; */
TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
processing = true; "TopMemoryContext",
8 * 1024,
if (on) 8 * 1024,
{ /* initialize */ 8 * 1024);
/* initialize TopGlobalMemoryData.setData */ /*
AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode, * Not having any other place to point CurrentMemoryContext,
(Size) 0); * make it point to TopMemoryContext. Caller should change this soon!
*/
/* make TopGlobalMemoryData member of ActiveGlobalMemorySet */ CurrentMemoryContext = TopMemoryContext;
OrderedSetInit(ActiveGlobalMemorySet, /*
offsetof(struct GlobalMemoryData, elemData)); * Initialize ErrorContext as an AllocSetContext with slow
OrderedElemPushInto(&TopGlobalMemoryData.elemData, * growth rate --- we don't really expect much to be allocated in it.
ActiveGlobalMemorySet); * 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
/* initialize CurrentMemoryContext */ * *essential* --- we want to be sure ErrorContext still has some
CurrentMemoryContext = TopMemoryContext; * memory even if we've run out elsewhere!
*/
} ErrorContext = AllocSetContextCreate(TopMemoryContext,
else "ErrorContext",
{ /* cleanup */ 8 * 1024,
GlobalMemory context; 8 * 1024,
8 * 1024);
/* 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;
} }
/* /*
* MemoryContextAlloc * MemoryContextReset
* Returns pointer to aligned allocated memory in the given context. * Release all space allocated within a context and its descendants,
* * but don't delete the contexts themselves.
* Note:
* none
* *
* Exceptions: * The type-specific reset routine handles the context itself, but we
* BadState if called before InitMemoryManager. * have to do the recursion for the children.
* BadArg if context is invalid or if size is 0.
* BadAllocSize if size is larger than MaxAllocSize.
*/ */
Pointer void
MemoryContextAlloc(MemoryContext context, Size size) MemoryContextReset(MemoryContext context)
{ {
AssertState(MemoryContextEnabled); MemoryContextResetChildren(context);
AssertArg(MemoryContextIsValid(context)); (*context->methods->reset) (context);
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
("size=%d [0x%x]", size, size));
return context->method->alloc(context, size);
} }
/* /*
* MemoryContextFree * MemoryContextResetChildren
* Frees allocated memory referenced by pointer in the given context. * Release all space allocated within a context's descendants,
* * but don't delete the contexts themselves. The named context
* Note: * itself is not touched.
* none
*
* Exceptions:
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
*/ */
void void
MemoryContextFree(MemoryContext context, Pointer pointer) MemoryContextResetChildren(MemoryContext context)
{ {
AssertState(MemoryContextEnabled); MemoryContext child;
AssertArg(MemoryContextIsValid(context));
AssertArg(PointerIsValid(pointer));
context->method->free_p(context, pointer); for (child = context->firstchild; child != NULL; child = child->nextchild)
{
MemoryContextReset(child);
}
} }
/* /*
* MemoryContextRelloc * MemoryContextDelete
* Returns pointer to aligned allocated memory in the given context. * Delete a context and its descendants, and release all space
* allocated therein.
* *
* Note: * The type-specific delete routine removes all subsidiary storage
* none * 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
* Exceptions: * node from its parent, if it has one.
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
*/ */
Pointer void
MemoryContextRealloc(MemoryContext context, MemoryContextDelete(MemoryContext context)
Pointer pointer,
Size size)
{ {
AssertState(MemoryContextEnabled); /* We had better not be deleting TopMemoryContext ... */
AssertArg(MemoryContextIsValid(context)); Assert(context != TopMemoryContext);
AssertArg(PointerIsValid(pointer)); /* 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, if (context == parent->firstchild)
("size=%d [0x%x]", size, size)); {
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 * MemoryContextDeleteChildren
* Returns pointer to aligned allocated memory in the given context. * Delete all the descendants of the named context and release all
* * space allocated therein. The named context itself is not touched.
* Note:
* none
*
* Exceptions:
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
*/ */
#ifdef NOT_USED void
char * MemoryContextDeleteChildren(MemoryContext context)
MemoryContextGetName(MemoryContext context)
{ {
AssertState(MemoryContextEnabled); /*
AssertArg(MemoryContextIsValid(context)); * MemoryContextDelete will delink the child from me,
* so just iterate as long as there is a child.
return context->method->getName(context); */
while (context->firstchild != NULL)
{
MemoryContextDelete(context->firstchild);
}
} }
#endif
/* /*
* PointerGetAllocSize * MemoryContextResetAndDeleteChildren
* Returns size of aligned allocated memory given pointer to it. * Release all space allocated within a context and delete all
* its descendants.
* *
* Note: * This is a common combination case where we want to preserve the
* none * specific context but get rid of absolutely everything under it.
*
* Exceptions:
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
*/ */
#ifdef NOT_USED void
Size MemoryContextResetAndDeleteChildren(MemoryContext context)
PointerGetAllocSize(Pointer pointer)
{ {
AssertState(MemoryContextEnabled); MemoryContextDeleteChildren(context);
AssertArg(PointerIsValid(pointer)); (*context->methods->reset) (context);
return PSIZE(pointer);
} }
#endif
/* /*
* MemoryContextSwitchTo * MemoryContextStats
* Returns the current context; installs the given context. * Print statistics about the named context and all its descendants.
* *
* Note: * This is just a debugging utility, so it's not fancy. The statistics
* none * are merely sent to stderr.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if context is invalid.
*/ */
MemoryContext void
MemoryContextSwitchTo(MemoryContext context) MemoryContextStats(MemoryContext context)
{ {
MemoryContext old; MemoryContext child;
AssertState(MemoryContextEnabled); (*context->methods->stats) (context);
AssertArg(MemoryContextIsValid(context)); for (child = context->firstchild; child != NULL; child = child->nextchild)
{
old = CurrentMemoryContext; MemoryContextStats(child);
CurrentMemoryContext = context; }
return old;
} }
/* /*
* External Functions * MemoryContextContains
*/ * Detect whether an allocated chunk of memory belongs to a given
/* * context or not.
* CreateGlobalMemory
* Returns new global memory context.
*
* Note:
* Assumes name is static.
* *
* Exceptions: * Caution: this test is reliable as long as 'pointer' does point to
* BadState if called when disabled. * a chunk of memory allocated from *some* context. If 'pointer' points
* BadState if called outside TopMemoryContext (TopGlobalMemory). * at memory obtained in some other way, there is a small chance of a
* BadArg if name is invalid. * false-positive result, since the bits right before it might look like
* a valid chunk header by chance.
*/ */
GlobalMemory bool
CreateGlobalMemory(char *name) /* XXX MemoryContextName */ MemoryContextContains(MemoryContext context, void *pointer)
{ {
GlobalMemory context; StandardChunkHeader *header;
MemoryContext savecxt;
/*
AssertState(MemoryContextEnabled); * Try to detect bogus pointers handed to us, poorly though we can.
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at
savecxt = MemoryContextSwitchTo(TopMemoryContext); * an allocated chunk.
*/
context = (GlobalMemory) newNode(sizeof(struct GlobalMemoryData), T_GlobalMemory); if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
context->method = &GlobalContextMethodsData; return false;
context->name = name; /* assumes name is static */ /*
AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0); * OK, it's probably safe to look at the chunk header.
*/
/* link the context */ header = (StandardChunkHeader *)
OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet); ((char *) pointer - STANDARDCHUNKHEADERSIZE);
/*
MemoryContextSwitchTo(savecxt); * If the context link doesn't match then we certainly have a
return context; * 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 * MemoryContextCreate
* Destroys given global memory context. * 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: * Normally, the context node and the name are allocated from
* BadState if called when disabled. * TopMemoryContext (NOT from the parent context, since the node must
* BadState if called outside TopMemoryContext (TopGlobalMemory). * survive resets of its parent context!). However, this routine is itself
* BadArg if context is invalid GlobalMemory. * used to create TopMemoryContext! If we see that TopMemoryContext is NULL,
* BadArg if context is TopMemoryContext (TopGlobalMemory). * 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 MemoryContext
GlobalMemoryDestroy(GlobalMemory context) MemoryContextCreate(NodeTag tag, Size size,
MemoryContextMethods *methods,
MemoryContext parent,
const char *name)
{ {
AssertState(MemoryContextEnabled); MemoryContext node;
AssertArg(IsA(context, GlobalMemory)); Size needed = size + strlen(name) + 1;
AssertArg(context != &TopGlobalMemoryData);
AllocSetReset(&context->setData); /* Get space for node and name */
if (TopMemoryContext != NULL)
/* unlink and delete the context */ {
OrderedElemPop(&context->elemData); /* Normal case: allocate the node in TopMemoryContext */
MemoryContextFree(TopMemoryContext, (Pointer) context); node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
} needed);
}
else
{
/* Special case for startup: use good ol' malloc */
node = (MemoryContext) malloc(needed);
Assert(node != NULL);
}
/***************************************************************************** /* Initialize the node as best we can */
* PRIVATE * 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;
}
/* /* Return to type-specific creation routine to finish up */
* GlobalMemoryAlloc return node;
* 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);
} }
/* /*
* GlobalMemoryFree * MemoryContextAlloc
* Frees allocated memory in the global context. * Allocate space within the specified context.
* *
* Exceptions: * This could be turned into a macro, but we'd have to import
* BadContextErr if current context is not the global context. * nodes/memnodes.h into postgres.h which seems a bad idea.
* BadArgumentsErr if pointer is invalid.
*/ */
static void void *
GlobalMemoryFree(GlobalMemory this, MemoryContextAlloc(MemoryContext context, Size size)
Pointer pointer)
{ {
AllocSetFree(&this->setData, pointer); AssertArg(MemoryContextIsValid(context));
}
/* LogTrap(!AllocSizeIsValid(size), BadAllocSize,
* GlobalMemoryRealloc ("size=%d [0x%x]", size, size));
* Returns pointer to aligned space in the global context.
* return (*context->methods->alloc) (context, size);
* 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);
} }
/* /*
* GlobalMemoryGetName * pfree
* Returns name string for context. * Release an allocated chunk.
*
* Exceptions:
* ???
*/ */
static char * void
GlobalMemoryGetName(GlobalMemory this) 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 * repalloc
* Dumps global memory context for debugging.
* *
* Exceptions:
* ???
*/ */
static void void *
GlobalMemoryDump(GlobalMemory this) repalloc(void *pointer, Size size)
{ {
GlobalMemory context; StandardChunkHeader *header;
printf("--\n%s:\n", GlobalMemoryGetName(this)); /*
* 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); LogTrap(!AllocSizeIsValid(size), BadAllocSize,
if (PointerIsValid(context)) ("size=%d [0x%x]", size, size));
printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
context = (GlobalMemory) OrderedElemGetSuccessor(&this->elemData);
if (PointerIsValid(context))
printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
AllocSetDump(&this->setData); return (*header->context->methods->realloc) (header->context,
pointer, size);
} }
/* /*
* DumpGlobalMemories * MemoryContextSwitchTo
* Dumps all global memory contexts for debugging. * Returns the current context; installs the given context.
*
* Exceptions:
* ???
*/ */
#ifdef NOT_USED MemoryContext
static void MemoryContextSwitchTo(MemoryContext context)
DumpGlobalMemories()
{ {
GlobalMemory context; MemoryContext old;
context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
while (PointerIsValid(context)) AssertArg(MemoryContextIsValid(context));
{
GlobalMemoryDump(context);
context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData); old = CurrentMemoryContext;
} CurrentMemoryContext = context;
return old;
} }
#endif
/* /*
* GlobalMemoryStats * MemoryContextStrdup
* Displays stats about memory consumption of all global contexts. * Like strdup(), but allocate from the specified context
*/ */
void char *
GlobalMemoryStats(void) 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)) memcpy(nstr, string, len);
{
AllocSetStats(&context->setData, GlobalMemoryGetName(context)); return nstr;
context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
}
} }
/*-------------------------------------------------------------------------
*
* 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;
}
/*-------------------------------------------------------------------------
*
* 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;
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -40,67 +40,28 @@
* *
* struct PortalD { * struct PortalD {
* char* name; * char* name;
* classObj(PortalVariableMemory) variable; * classObj(MemoryContext) heap;
* classObj(PortalHeapMemory) heap;
* List queryDesc; * List queryDesc;
* EState state; * EState state;
* void (*cleanup) ARGS((Portal portal)); * void (*cleanup) ARGS((Portal portal));
* }; * };
* *
* I hope this makes things clearer to whoever reads this -cim 2/22/91 * 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 "postgres.h"
#include "lib/hasht.h" #include "lib/hasht.h"
#include "utils/module.h" #include "utils/memutils.h"
#include "utils/portal.h" #include "utils/portal.h"
static void CollectNamedPortals(Portal *portalP, int destroy); 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 * Global state
* ---------------- * ----------------
*/ */
static int PortalManagerEnableCount = 0;
#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */ #define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
typedef struct portalhashent typedef struct portalhashent
...@@ -109,8 +70,6 @@ typedef struct portalhashent ...@@ -109,8 +70,6 @@ typedef struct portalhashent
Portal portal; Portal portal;
} PortalHashEnt; } PortalHashEnt;
#define PortalManagerEnabled (PortalManagerEnableCount >= 1)
static HTAB *PortalHashTable = NULL; static HTAB *PortalHashTable = NULL;
#define PortalHashTableLookup(NAME, PORTAL) \ #define PortalHashTableLookup(NAME, PORTAL) \
...@@ -158,263 +117,13 @@ do { \ ...@@ -158,263 +117,13 @@ do { \
elog(NOTICE, "trying to delete portal name that does not exist."); \ elog(NOTICE, "trying to delete portal name that does not exist."); \
} while(0) } while(0)
static GlobalMemory PortalMemory = NULL; static MemoryContext 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 */
};
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* private internal support routines * 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 * This routine is used to collect all portals created in this xaction
...@@ -447,12 +156,6 @@ CollectNamedPortals(Portal *portalP, int destroy) ...@@ -447,12 +156,6 @@ CollectNamedPortals(Portal *portalP, int destroy)
Assert(portalP); Assert(portalP);
Assert(*portalP); Assert(*portalP);
/*
* Don't delete special portals, up to portal creator to do this
*/
if (PortalNameIsSpecial((*portalP)->name))
return;
portalList[listIndex] = *portalP; portalList[listIndex] = *portalP;
listIndex++; listIndex++;
if (listIndex == maxIndex) if (listIndex == maxIndex)
...@@ -472,179 +175,50 @@ AtEOXact_portals() ...@@ -472,179 +175,50 @@ AtEOXact_portals()
CollectNamedPortals(NULL, 1); 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 * public portal interface functions
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
/* /*
* EnablePortalManager * EnablePortalManager
* Enables/disables the portal management module. * Enables the portal management module at backend startup.
*/ */
void void
EnablePortalManager(bool on) EnablePortalManager(void)
{ {
static bool processing = false;
HASHCTL ctl; HASHCTL ctl;
AssertState(!processing); Assert(PortalMemory == NULL);
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;
GlobalMemoryDestroy(PortalMemory); PortalMemory = AllocSetContextCreate(TopMemoryContext,
PortalMemory = NULL; "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 * GetPortalByName
* Returns a portal given a portal name; returns blank portal given * Returns a portal given a portal name, or NULL if name not found.
* NULL; returns invalid portal if portal not found.
*
* Exceptions:
* BadState if called when disabled.
*/ */
Portal Portal
GetPortalByName(char *name) GetPortalByName(char *name)
{ {
Portal portal; Portal portal;
AssertState(PortalManagerEnabled);
if (PointerIsValid(name)) if (PointerIsValid(name))
PortalHashTableLookup(name, portal); PortalHashTableLookup(name, portal);
else else
{ portal = NULL;
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);
return portal; return portal;
} }
...@@ -666,7 +240,6 @@ PortalSetQuery(Portal portal, ...@@ -666,7 +240,6 @@ PortalSetQuery(Portal portal,
EState *state, EState *state,
void (*cleanup) (Portal portal)) void (*cleanup) (Portal portal))
{ {
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
AssertArg(IsA((Node *) state, EState)); AssertArg(IsA((Node *) state, EState));
...@@ -687,7 +260,6 @@ PortalSetQuery(Portal portal, ...@@ -687,7 +260,6 @@ PortalSetQuery(Portal portal,
QueryDesc * QueryDesc *
PortalGetQueryDesc(Portal portal) PortalGetQueryDesc(Portal portal)
{ {
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
return portal->queryDesc; return portal->queryDesc;
...@@ -704,7 +276,6 @@ PortalGetQueryDesc(Portal portal) ...@@ -704,7 +276,6 @@ PortalGetQueryDesc(Portal portal)
EState * EState *
PortalGetState(Portal portal) PortalGetState(Portal portal)
{ {
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
return portal->state; return portal->state;
...@@ -714,63 +285,48 @@ PortalGetState(Portal portal) ...@@ -714,63 +285,48 @@ PortalGetState(Portal portal)
* CreatePortal * CreatePortal
* Returns a new portal given a name. * Returns a new portal given a name.
* *
* Note:
* This is expected to be of very limited usability. See instead,
* BlankPortalAssignName.
*
* Exceptions: * Exceptions:
* BadState if called when disabled. * BadState if called when disabled.
* BadArg if portal name is invalid. * 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 Portal
CreatePortal(char *name) /* XXX PortalName */ CreatePortal(char *name)
{ {
Portal portal; Portal portal;
uint16 length;
AssertState(PortalManagerEnabled); AssertArg(PointerIsValid(name));
AssertArg(PointerIsValid(name)); /* XXX PortalName */
portal = GetPortalByName(name); portal = GetPortalByName(name);
if (PortalIsValid(portal)) if (PortalIsValid(portal))
{ {
elog(NOTICE, "CreatePortal: portal %s already exists", name); elog(NOTICE, "CreatePortal: portal \"%s\" already exists", name);
return portal; return portal;
} }
/* make new portal structure */ /* make new portal structure */
portal = (Portal) portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
/* initialize portal variable context */ /* initialize portal name */
NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory); portal->name = MemoryContextStrdup(PortalMemory, name);
AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
portal->variable.method = &PortalVariableContextMethodsData;
/* initialize portal heap context */ /* initialize portal heap context */
NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory); portal->heap = AllocSetContextCreate(PortalMemory,
portal->heap.block = NULL; "PortalHeapMemory",
FixedStackInit(&portal->heap.stackData, ALLOCSET_DEFAULT_MINSIZE,
offsetof(HeapMemoryBlockData, itemData)); ALLOCSET_DEFAULT_INITSIZE,
portal->heap.method = &PortalHeapContextMethodsData; ALLOCSET_DEFAULT_MAXSIZE);
/* initialize portal name */
length = 1 + strlen(name);
portal->name = (char *)
MemoryContextAlloc((MemoryContext) &portal->variable, length);
strncpy(portal->name, name, length);
/* initialize portal query */ /* initialize portal query */
portal->queryDesc = NULL; portal->queryDesc = NULL;
portal->attinfo = NULL; portal->attinfo = NULL;
portal->state = NULL; portal->state = NULL;
portal->cleanup = NULL; portal->cleanup = NULL;
/* put portal in table */ /* put portal in table */
PortalHashTableInsert(portal); PortalHashTableInsert(portal);
/* Trap(PointerIsValid(name), Unimplemented); */
return portal; return portal;
} }
...@@ -787,240 +343,29 @@ PortalDrop(Portal *portalP) ...@@ -787,240 +343,29 @@ PortalDrop(Portal *portalP)
{ {
Portal portal = *portalP; Portal portal = *portalP;
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
/* remove portal from table if not blank portal */ /* remove portal from hash table */
if (portal != BlankPortal) PortalHashTableDelete(portal);
PortalHashTableDelete(portal);
/* reset portal */ /* reset portal */
if (PointerIsValid(portal->cleanup)) if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal); (*portal->cleanup) (portal);
PortalResetHeapMemory(portal); /* release subsidiary storage */
MemoryContextFree((MemoryContext) &portal->variable, MemoryContextDelete(PortalGetHeapMemory(portal));
(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;
AssertState(PortalManagerEnabled); /* release name and portal data (both are in PortalMemory) */
AssertState(IsA(CurrentMemoryContext, PortalHeapMemory)); pfree(portal->name);
pfree(portal);
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;
} }
/* /*
* PortalGetHeapMemory * PortalGetHeapMemory
* Returns heap memory context for a given portal. * Returns heap memory context for a given portal.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if portal is invalid.
*/ */
PortalHeapMemory MemoryContext
PortalGetHeapMemory(Portal portal) PortalGetHeapMemory(Portal portal)
{ {
return &portal->heap; 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)));
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -16,7 +16,6 @@
#include "utils/portal.h" #include "utils/portal.h"
extern MemoryContext PortalExecutorHeapMemory;
/* /*
* PerformPortalFetch * PerformPortalFetch
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -22,20 +22,19 @@
* *
* Each active hashjoin has a HashJoinTable control block which is * Each active hashjoin has a HashJoinTable control block which is
* palloc'd in the executor's context. All other storage needed for * 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 * This makes it easy and fast to release the storage when we don't need it
* anymore. * anymore.
* *
* The portal manager guarantees that portals will be discarded at end of * The contexts are made children of TransactionCommandContext, ensuring
* transaction, so we have no problem with a memory leak if the join is * 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 * 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.) * 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 * Storage that should live through the entire join is allocated from the
* portal's "variable context", while storage that is only wanted for the * "hashCxt", while storage that is only wanted for the current batch is
* current batch is allocated in the portal's "heap context". By popping * allocated in the "batchCxt". By resetting the batchCxt at the end of
* the portal's heap at the end of a batch, we free all the per-batch storage * each batch, we free all the per-batch storage reliably and without tedium.
* reliably and without tedium.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
...@@ -80,15 +79,6 @@ typedef struct HashTableData ...@@ -80,15 +79,6 @@ typedef struct HashTableData
* to hash buckets and output. * 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 hashCxt; /* context for whole-hash-join storage */
MemoryContext batchCxt; /* context for this-batch-only storage */ MemoryContext batchCxt; /* context for this-batch-only storage */
} HashTableData; } HashTableData;
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include "utils/fcache.h" #include "utils/fcache.h"
#include "utils/datum.h" #include "utils/datum.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/portal.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "catalog/pg_language.h" #include "catalog/pg_language.h"
#include "access/heapam.h" #include "access/heapam.h"
...@@ -95,4 +94,6 @@ extern void *SPI_repalloc(void *pointer, Size size); ...@@ -95,4 +94,6 @@ extern void *SPI_repalloc(void *pointer, Size size);
extern void SPI_pfree(void *pointer); extern void SPI_pfree(void *pointer);
extern void SPI_freetuple(HeapTuple pointer); extern void SPI_freetuple(HeapTuple pointer);
extern void AtEOXact_SPI(void);
#endif /* SPI_H */ #endif /* SPI_H */
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* spi.c * spi.c
* Server Programming Interface private declarations * 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 ...@@ -17,7 +17,8 @@ typedef struct
List *qtlist; List *qtlist;
uint32 processed; /* by Executor */ uint32 processed; /* by Executor */
SPITupleTable *tuptable; SPITupleTable *tuptable;
Portal portal; /* portal per procedure */ MemoryContext procCxt; /* procedure context */
MemoryContext execCxt; /* executor context */
MemoryContext savedcxt; MemoryContext savedcxt;
CommandId savedId; CommandId savedId;
} _SPI_connection; } _SPI_connection;
......
/*-------------------------------------------------------------------------
*
* 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 */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* This shouldn't be in libpq, but the monitor and some other * This shouldn't be in libpq, but the monitor and some other
...@@ -24,28 +24,18 @@ ...@@ -24,28 +24,18 @@
extern sigset_t UnBlockSig, extern sigset_t UnBlockSig,
BlockSig; BlockSig;
#define PG_INITMASK() ( \
sigemptyset(&UnBlockSig), \
sigfillset(&BlockSig) \
)
#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL) #define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)
#else #else
extern int UnBlockSig, extern int UnBlockSig,
BlockSig; 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))) #define PG_SETMASK(mask) sigsetmask(*((int*)(mask)))
#endif #endif
typedef void (*pqsigfunc) (int); typedef void (*pqsigfunc) (int);
extern void pqinitmask(void);
extern pqsigfunc pqsignal(int signo, pqsigfunc func); extern pqsigfunc pqsignal(int signo, pqsigfunc func);
#endif /* PQSIGNAL_H */ #endif /* PQSIGNAL_H */
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* some of the information in this file will be moved to * some of the information in this file will be moved to
...@@ -105,8 +105,6 @@ extern bool enableFsync; ...@@ -105,8 +105,6 @@ extern bool enableFsync;
extern bool allowSystemTableMods; extern bool allowSystemTableMods;
extern int SortMem; extern int SortMem;
extern Oid LastOidProcessed; /* for query rewrite */
/* a few postmaster startup options are exported here so the /* a few postmaster startup options are exported here so the
configuration file processor has access to them */ configuration file processor has access to them */
...@@ -189,9 +187,10 @@ typedef int16 ExitStatus; ...@@ -189,9 +187,10 @@ typedef int16 ExitStatus;
/* in utils/init/postinit.c */ /* in utils/init/postinit.c */
extern bool PostgresIsInitialized; extern int lockingOff;
extern void InitPostgres(const char *dbname); extern void InitPostgres(const char *dbname);
extern void BaseInit(void);
/* one of the ways to get out of here */ /* one of the ways to get out of here */
#define ExitPostgres(status) proc_exec(status) #define ExitPostgres(status) proc_exec(status)
......
...@@ -7,100 +7,88 @@ ...@@ -7,100 +7,88 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef MEMNODES_H
#define MEMNODES_H #define MEMNODES_H
#include "lib/fstack.h"
#include "nodes/nodes.h" #include "nodes/nodes.h"
#include "utils/memutils.h"
/* /*
* MemoryContext * MemoryContext
* A logical context in which memory allocations occur. * A logical context in which memory allocations occur.
* *
* The types of memory contexts can be thought of as members of the * MemoryContext itself is an abstract type that can have multiple
* following inheritance hierarchy with properties summarized below. * 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 * Node types that are actual implementations of memory contexts must
* | * begin with the same fields as MemoryContext.
* MemoryContext___
* / \
* GlobalMemory PortalMemoryContext
* / \
* PortalVariableMemory PortalHeapMemory
* *
* Flushed at Flushed at Checkpoints * Note: for largely historical reasons, typedef MemoryContext is a pointer
* Transaction Portal * to the context struct rather than the struct type itself.
* Commit Close
*
* GlobalMemory n n n
* PortalVariableMemory n y n
* PortalHeapMemory y y y
*/ */
typedef struct MemoryContextMethodsData typedef struct MemoryContextMethods
{ {
Pointer (*alloc) (); void *(*alloc) (MemoryContext context, Size size);
void (*free_p) (); /* need to use free as a #define, so can't /* call this free_p in case someone #define's free() */
* use free */ void (*free_p) (MemoryContext context, void *pointer);
Pointer (*realloc) (); void *(*realloc) (MemoryContext context, void *pointer, Size size);
char *(*getName) (); void (*init) (MemoryContext context);
void (*dump) (); void (*reset) (MemoryContext context);
} *MemoryContextMethods; void (*delete) (MemoryContext context);
void (*stats) (MemoryContext context);
} MemoryContextMethods;
typedef struct MemoryContextData typedef struct MemoryContextData
{ {
NodeTag type; NodeTag type; /* identifies exact kind of context */
MemoryContextMethods method; 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; } 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 */ /*
* AllocSetContext is our standard implementation of MemoryContext.
typedef struct MemoryContextData *PortalMemoryContext; */
typedef struct AllocBlockData *AllocBlock; /* internal to aset.c */
typedef struct AllocChunkData *AllocChunk;
typedef struct PortalVariableMemoryData typedef struct AllocSetContext
{ {
NodeTag type; MemoryContextData header; /* Standard memory-context fields */
MemoryContextMethods method; /* Info about storage allocated in this context: */
AllocSetData setData; AllocBlock blocks; /* head of list of blocks in this set */
} *PortalVariableMemory; #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 * MemoryContextIsValid
* True iff memory context is valid. * True iff memory context is valid.
*
* Add new context types to the set accepted by this macro.
*/ */
#define MemoryContextIsValid(context) \ #define MemoryContextIsValid(context) \
(IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \ ((context) != NULL && \
IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory)) (IsA((context), AllocSetContext)))
#endif /* MEMNODES_H */ #endif /* MEMNODES_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -122,10 +122,7 @@ typedef enum NodeTag
*--------------------- *---------------------
*/ */
T_MemoryContext = 400, T_MemoryContext = 400,
T_GlobalMemory, T_AllocSetContext,
T_PortalMemoryContext,
T_PortalVariableMemory,
T_PortalHeapMemory,
/*--------------------- /*---------------------
* TAGS FOR VALUE NODES (pg_list.h) * TAGS FOR VALUE NODES (pg_list.h)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 */ ...@@ -65,7 +65,6 @@ extern int Geqo_random_seed; /* or negative to use current time */
extern RelOptInfo *geqo(Query *root); extern RelOptInfo *geqo(Query *root);
/* routines in geqo_eval.c */ /* routines in geqo_eval.c */
extern void geqo_eval_startup(void);
extern Cost geqo_eval(Query *root, Gene *tour, int num_gene); extern Cost geqo_eval(Query *root, Gene *tour, int num_gene);
extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count, extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count,
int num_gene, RelOptInfo *old_rel); int num_gene, RelOptInfo *old_rel);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1995, Regents of the University of California * 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 @@ ...@@ -39,7 +39,6 @@
#include "postgres_ext.h" #include "postgres_ext.h"
#include "c.h" #include "c.h"
#include "utils/elog.h" #include "utils/elog.h"
#include "utils/mcxt.h"
#include "utils/palloc.h" #include "utils/palloc.h"
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -63,14 +63,13 @@ typedef struct SHM_QUEUE
extern void ShmemIndexReset(void); extern void ShmemIndexReset(void);
extern void ShmemCreate(unsigned int key, unsigned int size); extern void ShmemCreate(unsigned int key, unsigned int size);
extern int InitShmem(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 int ShmemIsValid(unsigned long addr);
extern HTAB *ShmemInitHash(char *name, long init_size, long max_size, extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
HASHCTL *infoP, int hash_flags); HASHCTL *infoP, int hash_flags);
extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr); extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
extern SHMEM_OFFSET ShmemPIDDestroy(int pid); extern SHMEM_OFFSET ShmemPIDDestroy(int pid);
extern long *ShmemInitStruct(char *name, unsigned long size, extern void *ShmemInitStruct(char *name, Size size, bool *foundPtr);
bool *foundPtr);
typedef int TableID; typedef int TableID;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -15,20 +15,13 @@
#define PQUERY_H #define PQUERY_H
#include "executor/execdesc.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, extern EState *CreateExecutorState(void);
Plan *plan, EState *state, TupleDesc attinfo,
CommandDest dest);
extern void extern Portal PreparePortal(char *portalName);
ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
#endif /* pqueryIncluded */ #endif /* PQUERY_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * OLD COMMENTS
* This file was created so that other c files could get the two * This file was created so that other c files could get the two
...@@ -33,12 +33,11 @@ extern bool ShowPortNumber; ...@@ -33,12 +33,11 @@ extern bool ShowPortNumber;
#ifndef BOOTSTRAP_INCLUDE #ifndef BOOTSTRAP_INCLUDE
extern List *pg_parse_and_rewrite(char *query_string, extern List *pg_parse_and_rewrite(char *query_string,
Oid *typev, int nargs, Oid *typev, int nargs);
bool aclOverride);
extern Plan *pg_plan_query(Query *querytree); extern Plan *pg_plan_query(Query *querytree);
extern void pg_exec_query_dest(char *query_string, extern void pg_exec_query_dest(char *query_string,
CommandDest dest, CommandDest dest,
bool aclOverride); MemoryContext parse_context);
#endif /* BOOTSTRAP_INCLUDE */ #endif /* BOOTSTRAP_INCLUDE */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -75,8 +75,10 @@ typedef struct catcache
#define InvalidCatalogCacheId (-1) #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, extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
ItemPointer pointer); ItemPointer pointer);
extern void ResetSystemCache(void); extern void ResetSystemCache(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -84,8 +84,7 @@ typedef struct htab
char *segbase; /* segment base address for calculating char *segbase; /* segment base address for calculating
* pointer values */ * pointer values */
SEG_OFFSET *dir; /* 'directory' of segm starts */ SEG_OFFSET *dir; /* 'directory' of segm starts */
long *(*alloc) (); /* memory allocator (long * for alignment void *(*alloc) (Size); /* memory allocator */
* reasons) */
} HTAB; } HTAB;
typedef struct hashctl typedef struct hashctl
...@@ -99,7 +98,7 @@ typedef struct hashctl ...@@ -99,7 +98,7 @@ typedef struct hashctl
long max_dsize; /* limit to dsize if directory size is long max_dsize; /* limit to dsize if directory size is
* limited */ * limited */
long *segbase; /* base for calculating bucket + seg ptrs */ 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 *dir; /* directory if allocated already */
long *hctl; /* location of header information in shd long *hctl; /* location of header information in shd
* mem */ * mem */
......
/*-------------------------------------------------------------------------
*
* 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 */
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* memutils.h * memutils.h
* this file contains general memory alignment, allocation * This file contains declarations for memory allocation utility
* and manipulation stuff that used to be spread out * functions. These are functions that are not quite widely used
* between the following files: * enough to justify going in utils/palloc.h, but are still part
* * of the API of the memory management subsystem.
* align.h alignment macros
* aset.h memory allocation set stuff
* oset.h (used by aset.h)
* *
* *
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef MEMUTILS_H
#define MEMUTILS_H #define MEMUTILS_H
/* ---------------- #include "nodes/memnodes.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.
* ----------------
*/
#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: * MaxAllocSize
* An allocation set is a set containing allocated elements. When * Arbitrary limit on size of allocations.
* 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.
* *
* Note: * Note:
* Allocation sets are not automatically reset on a system reset. * There is no guarantee that allocations smaller than MaxAllocSize
* Higher level code is responsible for cleaning up. * 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 */
/* #define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
* AllocPointer
* Aligned pointer which may be a member of an allocation set.
*/
typedef Pointer AllocPointer;
/* /*
* AllocMode * All chunks allocated by any memory context manager are required to be
* Mode of allocation for an allocation set. * preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
* * A currently-allocated chunk must contain a backpointer to its owning
* Note: * context as well as the allocated size of the chunk. The backpointer is
* See above for a description of the various modes. * 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 */ MemoryContext context; /* owning context */
StaticAllocMode, /* always "statically" allocate */ Size size; /* size of data space allocated in chunk */
TunableAllocMode, /* allocations are "tuned" */ } StandardChunkHeader;
BoundedAllocMode /* allocations bounded to fixed usage */
} AllocMode;
#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 * Standard top-level memory contexts.
* 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 * Only TopMemoryContext and ErrorContext are initialized by
* within the block begins at the next alignment boundary. * MemoryContextInit() itself.
*/ */
typedef struct AllocBlockData extern MemoryContext TopMemoryContext;
{ extern MemoryContext ErrorContext;
AllocSet aset; /* aset that owns this block */ extern MemoryContext PostmasterContext;
AllocBlock next; /* next block in aset's blocks list */ extern MemoryContext CacheMemoryContext;
char *freeptr; /* start of free space in this block */ extern MemoryContext QueryContext;
char *endptr; /* end of space in this block */ extern MemoryContext TopTransactionContext;
} AllocBlockData; 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 * Memory-context-type-independent functions in mcxt.c
* True iff pointer is valid allocation pointer.
*/ */
#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 * This routine handles the context-type-independent part of memory
* True iff set is valid allocation set. * 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); /* aset.c */
extern AllocPointer AllocSetAlloc(AllocSet set, Size size); extern MemoryContext AllocSetContextCreate(MemoryContext parent,
extern void AllocSetFree(AllocSet set, AllocPointer pointer); const char *name,
extern AllocPointer AllocSetRealloc(AllocSet set, AllocPointer pointer, Size minContextSize,
Size size); 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 */ #endif /* MEMUTILS_H */
/*-------------------------------------------------------------------------
*
* 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 */
...@@ -3,36 +3,85 @@ ...@@ -3,36 +3,85 @@
* palloc.h * palloc.h
* POSTGRES memory allocator definitions. * 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) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef PALLOC_H
#define 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) extern void pfree(void *pointer);
#define pfree(p) free(p)
#define repalloc(p,s) realloc((p),(s))
#else /* ! PALLOC_IS_MALLOC */ extern void *repalloc(void *pointer, Size size);
/* ---------- extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
* In the case we use memory contexts, use macro's for palloc() etc.
* ---------- /*
* 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 */ #endif /* PALLOC_H */
...@@ -7,16 +7,14 @@ ...@@ -7,16 +7,14 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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: * Note:
* A portal is an abstraction which represents the execution state of * 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 running query (or a fixed sequence of queries).
* a portal with an InvalidName. This blank portal is in existance except
* between calls to BlankPortalAssignName and GetPortalByName(NULL).
* *
* Note: * Note:
* now that PQ calls can be made from within a backend, a portal * now that PQ calls can be made from within a backend, a portal
...@@ -29,27 +27,18 @@ ...@@ -29,27 +27,18 @@
#include "executor/execdesc.h" #include "executor/execdesc.h"
#include "nodes/memnodes.h" #include "nodes/memnodes.h"
typedef struct PortalBlockData
{
AllocSetData setData;
FixedItemData itemData;
} PortalBlockData;
typedef PortalBlockData *PortalBlock;
typedef struct PortalD PortalD; typedef struct PortalD *Portal;
typedef PortalD *Portal;
struct PortalD typedef struct PortalD
{ {
char *name; /* XXX PortalName */ char *name; /* Portal's name */
struct PortalVariableMemoryData variable; MemoryContext heap; /* subsidiary memory */
struct PortalHeapMemoryData heap; QueryDesc *queryDesc; /* Info about query associated with portal */
QueryDesc *queryDesc;
TupleDesc attinfo; TupleDesc attinfo;
EState *state; EState *state;
void (*cleanup) (Portal); void (*cleanup) (Portal); /* Cleanup routine (optional) */
}; } PortalD;
/* /*
* PortalIsValid * PortalIsValid
...@@ -57,36 +46,20 @@ struct PortalD ...@@ -57,36 +46,20 @@ struct PortalD
*/ */
#define PortalIsValid(p) PointerIsValid(p) #define PortalIsValid(p) PointerIsValid(p)
/* extern void EnablePortalManager(void);
* Special portals (well, their names anyway)
*/
#define VACPNAME "<vacuum>"
#define TRUNCPNAME "<truncate>"
extern bool PortalNameIsSpecial(char *pname);
extern void AtEOXact_portals(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 GetPortalByName(char *name);
extern Portal BlankPortalAssignName(char *name);
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc, extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
TupleDesc attinfo, EState *state, TupleDesc attinfo, EState *state,
void (*cleanup) (Portal portal)); void (*cleanup) (Portal portal));
extern QueryDesc *PortalGetQueryDesc(Portal portal); extern QueryDesc *PortalGetQueryDesc(Portal portal);
extern EState *PortalGetState(Portal portal); extern EState *PortalGetState(Portal portal);
extern Portal CreatePortal(char *name); extern MemoryContext PortalGetHeapMemory(Portal portal);
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);
/* estimate of the maximum number of open portals a user would have, /* 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 #define PORTALS_PER_USER 10
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment