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.
This commit is contained in:
Tom Lane 2000-06-28 03:33:33 +00:00
parent b601c8d882
commit 1aebc3618a
74 changed files with 2325 additions and 3296 deletions

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.9 2000/03/31 03:27:40 thomas Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.10 2000/06/28 03:30:53 tgl Exp $
Genetic Optimizer
-->
@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer
<Sect2>
<Title>Basic Improvements</Title>
<Sect3>
<Title>Improve freeing of memory when query is already processed</Title>
<Para>
With large <Command>join</Command> queries the computing time spent for the genetic query
optimization seems to be a mere <Emphasis>fraction</Emphasis> of the time
<ProductName>Postgres</ProductName>
needs for freeing memory via routine <Function>MemoryContextFree</Function>,
file <FileName>backend/utils/mmgr/mcxt.c</FileName>.
Debugging showed that it get stucked in a loop of routine
<Function>OrderedElemPop</Function>, file <FileName>backend/utils/mmgr/oset.c</FileName>.
The same problems arise with long queries when using the normal
<ProductName>Postgres</ProductName> query optimization algorithm.
</para>
</sect3>
<Sect3>
<Title>Improve genetic algorithm parameter settings</Title>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.8 1999/12/30 22:58:10 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.9 2000/06/28 03:30:54 tgl Exp $
Postgres documentation
-->
@ -153,12 +153,13 @@ SELECT
<varlistentry>
<term><computeroutput>
NOTICE
BlankPortalAssignName: portal "<replaceable class="parameter">cursorname</replaceable>" already exists
NOTICE: Closing pre-existing portal "<replaceable class="parameter">cursorname</replaceable>"
</computeroutput></term>
<listitem>
<para>
This error occurs if <replaceable class="parameter">cursorname</replaceable> is already declared.
This message is reported if the same cursor name was already declared
in the current transaction block. The previous definition is
discarded.
</para>
</listitem>
</varlistentry>

View File

@ -34,7 +34,7 @@
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.55 2000/06/17 00:09:34 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.56 2000/06/28 03:30:57 tgl Exp $
#
#-------------------------------------------------------------------------
@ -237,8 +237,6 @@ install-headers: prebuildheaders $(SRCDIR)/include/config.h
$(HEADERDIR)/utils/fmgroids.h
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \
$(HEADERDIR)/utils/palloc.h
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/mcxt.h \
$(HEADERDIR)/utils/mcxt.h
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/access/attnum.h \
$(HEADERDIR)/access/attnum.h
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.71 2000/06/15 04:09:34 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.72 2000/06/28 03:31:04 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -1230,10 +1230,7 @@ heap_insert(Relation relation, HeapTuple tup)
* ----------------
*/
if (!OidIsValid(tup->t_data->t_oid))
{
tup->t_data->t_oid = newoid();
LastOidProcessed = tup->t_data->t_oid;
}
else
CheckMaxObjectId(tup->t_data->t_oid);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.67 2000/06/18 22:43:51 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.68 2000/06/28 03:31:05 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@ -18,14 +18,14 @@
*
* These two cases used to be treated identically, but now
* we need to distinguish them. Why? consider the following
* two situatuons:
* two situations:
*
* case 1 case 2
* ------ ------
* 1) user types BEGIN 1) user types BEGIN
* 2) user does something 2) user does something
* 3) user does not like what 3) system aborts for some reason
* she shes and types ABORT
* she sees and types ABORT
*
* In case 1, we want to abort the transaction and return to the
* default state. In case 2, there may be more commands coming
@ -42,6 +42,15 @@
* * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
* * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
*
* Low-level transaction abort handling is divided into two phases:
* * AbortTransaction() executes as soon as we realize the transaction
* has failed. It should release all shared resources (locks etc)
* so that we do not delay other backends unnecessarily.
* * CleanupTransaction() executes when we finally see a user COMMIT
* or ROLLBACK command; it cleans things up and gets us out of
* the transaction internally. In particular, we mustn't destroy
* TransactionCommandContext until this point.
*
* NOTES
* This file is an attempt at a redesign of the upper layer
* of the V1 transaction system which was too poorly thought
@ -70,7 +79,7 @@
* StartTransaction
* CommitTransaction
* AbortTransaction
* UserAbortTransaction
* CleanupTransaction
*
* are provided to do the lower level work like recording
* the transaction status in the log and doing memory cleanup.
@ -151,13 +160,15 @@
#include "commands/async.h"
#include "commands/sequence.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "libpq/be-fsstubs.h"
#include "storage/proc.h"
#include "storage/sinval.h"
#include "utils/temprel.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/portal.h"
#include "utils/relcache.h"
#include "utils/temprel.h"
extern bool SharedBufferChanged;
@ -165,6 +176,7 @@ static void AbortTransaction(void);
static void AtAbort_Cache(void);
static void AtAbort_Locks(void);
static void AtAbort_Memory(void);
static void AtCleanup_Memory(void);
static void AtCommit_Cache(void);
static void AtCommit_LocalCache(void);
static void AtCommit_Locks(void);
@ -172,6 +184,7 @@ static void AtCommit_Memory(void);
static void AtStart_Cache(void);
static void AtStart_Locks(void);
static void AtStart_Memory(void);
static void CleanupTransaction(void);
static void CommitTransaction(void);
static void RecordTransactionAbort(void);
static void RecordTransactionCommit(void);
@ -243,7 +256,7 @@ bool AMI_OVERRIDE = false;
/* --------------------------------
* TranactionFlushEnabled()
* SetTranactionFlushEnabled()
* SetTransactionFlushEnabled()
*
* These are used to test and set the "TransactionFlushState"
* varable. If this variable is true (the default), then
@ -580,22 +593,35 @@ AtStart_Locks()
static void
AtStart_Memory()
{
Portal portal;
MemoryContext portalContext;
/* ----------------
* get the blank portal and its memory context
* We shouldn't have any transaction contexts already.
* ----------------
*/
portal = GetPortalByName(NULL);
portalContext = (MemoryContext) PortalGetHeapMemory(portal);
Assert(TopTransactionContext == NULL);
Assert(TransactionCommandContext == NULL);
/* ----------------
* tell system to allocate in the blank portal context
* Create a toplevel context for the transaction.
* ----------------
*/
MemoryContextSwitchTo(portalContext);
StartPortalAllocMode(DefaultAllocMode, 0);
TopTransactionContext =
AllocSetContextCreate(TopMemoryContext,
"TopTransactionContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* ----------------
* Create a statement-level context and make it active.
* ----------------
*/
TransactionCommandContext =
AllocSetContextCreate(TopTransactionContext,
"TransactionCommandContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
MemoryContextSwitchTo(TransactionCommandContext);
}
@ -711,22 +737,21 @@ AtCommit_Locks()
static void
AtCommit_Memory()
{
Portal portal;
/* ----------------
* Release all heap memory in the blank portal.
* ----------------
*/
portal = GetPortalByName(NULL);
PortalResetHeapMemory(portal);
/* ----------------
* Now that we're "out" of a transaction, have the
* system allocate things in the top memory context instead
* of the blank portal memory context.
* of per-transaction contexts.
* ----------------
*/
MemoryContextSwitchTo(TopMemoryContext);
/* ----------------
* Release all transaction-local memory.
* ----------------
*/
MemoryContextDelete(TopTransactionContext);
TopTransactionContext = NULL;
TransactionCommandContext = NULL;
}
/* ----------------------------------------------------------------
@ -798,24 +823,52 @@ AtAbort_Locks()
static void
AtAbort_Memory()
{
Portal portal;
/* ----------------
* Release all heap memory in the blank portal.
* Make sure we are in a valid context (not a child of
* TransactionCommandContext...)
* ----------------
*/
portal = GetPortalByName(NULL);
PortalResetHeapMemory(portal);
MemoryContextSwitchTo(TransactionCommandContext);
/* ----------------
* We do not want to destroy transaction contexts yet,
* but it should be OK to delete any command-local memory.
* ----------------
*/
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
}
/* ----------------------------------------------------------------
* CleanupTransaction stuff
* ----------------------------------------------------------------
*/
/* --------------------------------
* AtCleanup_Memory
* --------------------------------
*/
static void
AtCleanup_Memory()
{
/* ----------------
* Now that we're "out" of a transaction, have the
* system allocate things in the top memory context instead
* of the blank portal memory context.
* of per-transaction contexts.
* ----------------
*/
MemoryContextSwitchTo(TopMemoryContext);
/* ----------------
* Release all transaction-local memory.
* ----------------
*/
MemoryContextDelete(TopTransactionContext);
TopTransactionContext = NULL;
TransactionCommandContext = NULL;
}
/* ----------------------------------------------------------------
* interface routines
* ----------------------------------------------------------------
@ -854,6 +907,7 @@ StartTransaction()
s->state = TRANS_START;
SetReindexProcessing(false);
/* ----------------
* generate a new transaction id
* ----------------
@ -874,9 +928,9 @@ StartTransaction()
* initialize the various transaction subsystems
* ----------------
*/
AtStart_Memory();
AtStart_Cache();
AtStart_Locks();
AtStart_Memory();
/* ----------------
* Tell the trigger manager to we're starting a transaction
@ -974,20 +1028,21 @@ CommitTransaction()
}
RelationPurgeLocalRelation(true);
AtEOXact_SPI();
AtEOXact_nbtree();
AtCommit_Cache();
AtCommit_Locks();
AtCommit_Memory();
AtEOXact_Files();
SharedBufferChanged = false; /* safest place to do it */
/* ----------------
* done with commit processing, set current transaction
* state back to default
* ----------------
*/
s->state = TRANS_DEFAULT;
SharedBufferChanged = false;/* safest place to do it */
}
/* --------------------------------
@ -1018,7 +1073,7 @@ AbortTransaction()
return;
if (s->state != TRANS_INPROGRESS)
elog(NOTICE, "AbortTransaction and not in in-progress state ");
elog(NOTICE, "AbortTransaction and not in in-progress state");
/* ----------------
* Tell the trigger manager that this transaction is about to be
@ -1043,24 +1098,56 @@ AbortTransaction()
AtAbort_Notify();
CloseSequences();
AtEOXact_portals();
if (CommonSpecialPortalIsOpen())
CommonSpecialPortalClose();
RecordTransactionAbort();
RelationPurgeLocalRelation(false);
invalidate_temp_relations();
AtEOXact_SPI();
AtEOXact_nbtree();
AtAbort_Cache();
AtAbort_Locks();
AtAbort_Memory();
AtEOXact_Files();
SharedBufferChanged = false; /* safest place to do it */
/* ----------------
* State remains TRANS_ABORT until CleanupTransaction().
* ----------------
*/
}
/* --------------------------------
* CleanupTransaction
*
* --------------------------------
*/
static void
CleanupTransaction()
{
TransactionState s = CurrentTransactionState;
if (s->state == TRANS_DISABLED)
return;
/* ----------------
* State should still be TRANS_ABORT from AbortTransaction().
* ----------------
*/
if (s->state != TRANS_ABORT)
elog(FATAL, "CleanupTransaction and not in abort state");
/* ----------------
* do abort cleanup processing
* ----------------
*/
AtCleanup_Memory();
/* ----------------
* done with abort processing, set current transaction
* state back to default
* ----------------
*/
s->state = TRANS_DEFAULT;
SharedBufferChanged = false;/* safest place to do it */
}
/* --------------------------------
@ -1133,7 +1220,7 @@ StartTransactionCommand()
/* ----------------
* This means we somehow aborted and the last call to
* CommitTransactionCommand() didn't clear the state so
* we remain in the ENDABORT state and mabey next time
* we remain in the ENDABORT state and maybe next time
* we get to CommitTransactionCommand() the state will
* get reset to default.
* ----------------
@ -1142,6 +1229,13 @@ StartTransactionCommand()
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
break;
}
/*
* We must switch to TransactionCommandContext before returning.
* This is already done if we called StartTransaction, otherwise not.
*/
Assert(TransactionCommandContext != NULL);
MemoryContextSwitchTo(TransactionCommandContext);
}
/* --------------------------------
@ -1181,28 +1275,25 @@ CommitTransactionCommand()
* command counter and return. Someday we may free resources
* local to the command.
*
* That someday is today, at least for memory allocated by
* command in the BlankPortal' HeapMemory context.
* That someday is today, at least for memory allocated in
* TransactionCommandContext.
* - vadim 03/25/97
* ----------------
*/
case TBLOCK_INPROGRESS:
CommandCounterIncrement();
#ifdef TBL_FREE_CMD_MEMORY
EndPortalAllocMode();
StartPortalAllocMode(DefaultAllocMode, 0);
#endif
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
break;
/* ----------------
* This is the case when we just got the "END TRANSACTION"
* statement, so we go back to the default state and
* commit the transaction.
* statement, so we commit the transaction and go back to
* the default state.
* ----------------
*/
case TBLOCK_END:
s->blockState = TBLOCK_DEFAULT;
CommitTransaction();
s->blockState = TBLOCK_DEFAULT;
break;
/* ----------------
@ -1218,10 +1309,11 @@ CommitTransactionCommand()
/* ----------------
* Here we were in an aborted transaction block which
* just processed the "END TRANSACTION" command from the
* user, so now we return the to default state.
* user, so clean up and return to the default state.
* ----------------
*/
case TBLOCK_ENDABORT:
CleanupTransaction();
s->blockState = TBLOCK_DEFAULT;
break;
}
@ -1240,11 +1332,12 @@ AbortCurrentTransaction()
{
/* ----------------
* if we aren't in a transaction block, we
* just do our usual abort transaction.
* just do the basic abort & cleanup transaction.
* ----------------
*/
case TBLOCK_DEFAULT:
AbortTransaction();
CleanupTransaction();
break;
/* ----------------
@ -1257,6 +1350,7 @@ AbortCurrentTransaction()
case TBLOCK_BEGIN:
s->blockState = TBLOCK_ABORT;
AbortTransaction();
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
break;
/* ----------------
@ -1269,6 +1363,7 @@ AbortCurrentTransaction()
case TBLOCK_INPROGRESS:
s->blockState = TBLOCK_ABORT;
AbortTransaction();
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
break;
/* ----------------
@ -1281,6 +1376,7 @@ AbortCurrentTransaction()
case TBLOCK_END:
s->blockState = TBLOCK_DEFAULT;
AbortTransaction();
CleanupTransaction();
break;
/* ----------------
@ -1297,10 +1393,11 @@ AbortCurrentTransaction()
* Here we were in an aborted transaction block which
* just processed the "END TRANSACTION" command but somehow
* aborted again.. since we must have done the abort
* processing, we return to the default state.
* processing, we clean up and return to the default state.
* ----------------
*/
case TBLOCK_ENDABORT:
CleanupTransaction();
s->blockState = TBLOCK_DEFAULT;
break;
}
@ -1394,13 +1491,14 @@ EndTransactionBlock(void)
}
/* ----------------
* We should not get here, but if we do, we go to the ENDABORT
* state after printing a warning. The upcoming call to
* here, the user issued COMMIT when not inside a transaction.
* Issue a notice and go to abort state. The upcoming call to
* CommitTransactionCommand() will then put us back into the
* default state.
* ----------------
*/
elog(NOTICE, "COMMIT: no transaction in progress");
AbortTransaction();
s->blockState = TBLOCK_ENDABORT;
}
@ -1427,29 +1525,23 @@ AbortTransactionBlock(void)
* here we were inside a transaction block something
* screwed up inside the system so we enter the abort state,
* do the abort processing and then return.
* We remain in the abort state until we see the upcoming
* We remain in the abort state until we see an
* END TRANSACTION command.
* ----------------
*/
s->blockState = TBLOCK_ABORT;
/* ----------------
* do abort processing and return
* ----------------
*/
AbortTransaction();
return;
}
/* ----------------
* this case should not be possible, because it would mean
* the user entered an "abort" from outside a transaction block.
* So we print an error message, abort the transaction and
* enter the "ENDABORT" state so we will end up in the default
* state after the upcoming CommitTransactionCommand().
* here, the user issued ABORT when not inside a transaction.
* Issue a notice and go to abort state. The upcoming call to
* CommitTransactionCommand() will then put us back into the
* default state.
* ----------------
*/
elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
elog(NOTICE, "ROLLBACK: no transaction in progress");
AbortTransaction();
s->blockState = TBLOCK_ENDABORT;
}
@ -1495,27 +1587,16 @@ UserAbortTransactionBlock()
* ----------------
*/
s->blockState = TBLOCK_ABORT;
/* ----------------
* do abort processing
* ----------------
*/
AbortTransaction();
/* ----------------
* change to the end abort state and return
* ----------------
*/
s->blockState = TBLOCK_ENDABORT;
return;
}
/* ----------------
* this case should not be possible, because it would mean
* the user entered a "rollback" from outside a transaction block.
* So we print an error message, abort the transaction and
* enter the "ENDABORT" state so we will end up in the default
* state after the upcoming CommitTransactionCommand().
* here, the user issued ABORT when not inside a transaction.
* Issue a notice and go to abort state. The upcoming call to
* CommitTransactionCommand() will then put us back into the
* default state.
* ----------------
*/
elog(NOTICE, "ROLLBACK: no transaction in progress");
@ -1540,7 +1621,10 @@ AbortOutOfAnyTransaction()
* Get out of any low-level transaction
*/
if (s->state != TRANS_DEFAULT)
{
AbortTransaction();
CleanupTransaction();
}
/*
* Now reset the high-level state

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.87 2000/06/22 22:31:17 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.88 2000/06/28 03:31:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -34,14 +34,14 @@
#include "miscadmin.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/exc.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/portal.h"
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
extern void BaseInit(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(void);
extern void BootStrapXLOG(void);
@ -144,8 +144,8 @@ static Datum values[MAXATTR]; /* corresponding attribute values */
int numattr; /* number of attributes for cur. rel */
int DebugMode;
static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
* context */
static MemoryContext nogc = NULL; /* special no-gc mem context */
extern int optind;
extern char *optarg;
@ -240,6 +240,17 @@ BootstrapMain(int argc, char *argv[])
MyProcPid = getpid();
/*
* Fire up essential subsystems: error and memory management
*
* If we are running under the postmaster, this is done already.
*/
if (!IsUnderPostmaster)
{
EnableExceptionHandling(true);
MemoryContextInit();
}
/* ----------------
* process command arguments
* ----------------
@ -428,7 +439,6 @@ boot_openrel(char *relname)
if (Typ == (struct typmap **) NULL)
{
StartPortalAllocMode(DefaultAllocMode, 0);
rel = heap_openr(TypeRelationName, NoLock);
Assert(rel);
scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
@ -445,13 +455,13 @@ boot_openrel(char *relname)
while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
{
(*app)->am_oid = tup->t_data->t_oid;
memmove((char *) &(*app++)->am_typ,
(char *) GETSTRUCT(tup),
sizeof((*app)->am_typ));
memcpy((char *) &(*app)->am_typ,
(char *) GETSTRUCT(tup),
sizeof((*app)->am_typ));
app++;
}
heap_endscan(scan);
heap_close(rel, NoLock);
EndPortalAllocMode();
}
if (reldesc != NULL)
@ -1088,10 +1098,14 @@ index_register(char *heap,
* them later.
*/
if (nogc == (GlobalMemory) NULL)
nogc = CreateGlobalMemory("BootstrapNoGC");
if (nogc == NULL)
nogc = AllocSetContextCreate((MemoryContext) NULL,
"BootstrapNoGC",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
oldcxt = MemoryContextSwitchTo(nogc);
newind = (IndexList *) palloc(sizeof(IndexList));
newind->il_heap = pstrdup(heap);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.133 2000/06/18 22:43:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.134 2000/06/28 03:31:22 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -188,38 +188,27 @@ heap_create(char *relname,
relname);
}
/* ----------------
* switch to the cache context so that we don't lose
* allocations at the end of this transaction, I guess.
* -cim 6/14/90
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
/* ----------------
* real ugly stuff to assign the proper relid in the relation
* descriptor follows.
* ----------------
*/
if (relname && !strcmp(RelationRelationName, relname))
if (relname && strcmp(RelationRelationName, relname) == 0)
{
relid = RelOid_pg_class;
nailme = true;
}
else if (relname && !strcmp(AttributeRelationName, relname))
else if (relname && strcmp(AttributeRelationName, relname) == 0)
{
relid = RelOid_pg_attribute;
nailme = true;
}
else if (relname && !strcmp(ProcedureRelationName, relname))
else if (relname && strcmp(ProcedureRelationName, relname) == 0)
{
relid = RelOid_pg_proc;
nailme = true;
}
else if (relname && !strcmp(TypeRelationName, relname))
else if (relname && strcmp(TypeRelationName, relname) == 0)
{
relid = RelOid_pg_type;
nailme = true;
@ -234,6 +223,15 @@ heap_create(char *relname,
(int) MyProcPid, uniqueId++);
}
/* ----------------
* switch to the cache context to create the relcache entry.
* ----------------
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* allocate a new relation descriptor.
* ----------------
@ -287,6 +285,8 @@ heap_create(char *relname,
/* ----------------
* have the storage manager create the relation.
*
* XXX shouldn't we switch out of CacheMemoryContext for that?
* ----------------
*/

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.119 2000/06/18 22:43:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.120 2000/06/28 03:31:23 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -442,10 +442,10 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
* context changes
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
@ -904,16 +904,16 @@ InitIndexStrategy(int numatts,
* it will be lost at the end of the transaction.
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
if (!CacheMemoryContext)
CreateCacheMemoryContext();
strategy = (IndexStrategy)
MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
strsize);
if (amsupport > 0)
{
strsize = numatts * (amsupport * sizeof(RegProcedure));
support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
strsize);
}
else

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.44 2000/06/14 04:53:44 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.45 2000/06/28 03:31:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -217,8 +217,7 @@ ProcedureCreate(char *procedureName,
if (languageObjectId == SQLlanguageId)
{
querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount,
FALSE);
querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount);
/* typecheck return value */
pg_checkretval(typeObjectId, querytree_list);
}

View File

@ -8,13 +8,9 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.80 2000/06/15 04:09:45 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.81 2000/06/28 03:31:28 tgl Exp $
*
* NOTES
* The PortalExecutorHeapMemory crap needs to be eliminated
* by designing a better executor / portal processing memory
* interface.
*
* The PerformAddAttribute() code, like most of the relation
* manipulating code in the commands/ directory, should go
* someplace closer to the lib/catalog code.
@ -40,13 +36,6 @@
#include "parser/parse.h"
#endif /* _DROP_COLUMN_HACK__ */
/* ----------------
* PortalExecutorHeapMemory stuff
*
* This is where the XXXSuperDuperHacky code was. -cim 3/15/90
* ----------------
*/
MemoryContext PortalExecutorHeapMemory = NULL;
/* --------------------------------
* PortalCleanup
@ -55,7 +44,7 @@ MemoryContext PortalExecutorHeapMemory = NULL;
void
PortalCleanup(Portal portal)
{
MemoryContext context;
MemoryContext oldcontext;
/* ----------------
* sanity checks
@ -68,8 +57,7 @@ PortalCleanup(Portal portal)
* set proper portal-executor context before calling ExecMain.
* ----------------
*/
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
/* ----------------
* tell the executor to shutdown the query
@ -81,8 +69,7 @@ PortalCleanup(Portal portal)
* switch back to previous context
* ----------------
*/
MemoryContextSwitchTo(context);
PortalExecutorHeapMemory = (MemoryContext) NULL;
MemoryContextSwitchTo(oldcontext);
}
/* --------------------------------
@ -99,7 +86,7 @@ PerformPortalFetch(char *name,
Portal portal;
int feature;
QueryDesc *queryDesc;
MemoryContext context;
MemoryContext oldcontext;
Const limcount;
/* ----------------
@ -108,7 +95,7 @@ PerformPortalFetch(char *name,
*/
if (name == NULL)
{
elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
elog(NOTICE, "PerformPortalFetch: missing portal name");
return;
}
@ -120,12 +107,11 @@ PerformPortalFetch(char *name,
limcount.type = T_Const;
limcount.consttype = INT4OID;
limcount.constlen = sizeof(int4);
limcount.constvalue = (Datum) count;
limcount.constisnull = FALSE;
limcount.constbyval = TRUE;
limcount.constisset = FALSE;
limcount.constiscast = FALSE;
limcount.constvalue = Int32GetDatum(count);
limcount.constisnull = false;
limcount.constbyval = true;
limcount.constisset = false;
limcount.constiscast = false;
/* ----------------
* get the portal from the portal name
@ -143,9 +129,7 @@ PerformPortalFetch(char *name,
* switch into the portal context
* ----------------
*/
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
/* ----------------
* setup "feature" to tell the executor what direction and
@ -174,8 +158,7 @@ PerformPortalFetch(char *name,
BeginCommand(name,
queryDesc->operation,
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
* */
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc) */
false, /* portal fetches don't end up in
* relations */
false, /* this is a portal fetch, not a "retrieve
@ -187,8 +170,6 @@ PerformPortalFetch(char *name,
* execute the portal fetch operation
* ----------------
*/
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
ExecutorRun(queryDesc, PortalGetState(portal), feature,
(Node *) NULL, (Node *) &limcount);
@ -196,18 +177,16 @@ PerformPortalFetch(char *name,
pfree(queryDesc);
/* ----------------
* Note: the "end-of-command" tag is returned by higher-level
* utility code
*
* Return blank portal for now.
* Otherwise, this named portal will be cleaned.
* Note: portals will only be supported within a BEGIN...END
* block in the near future. Later, someone will fix it to
* do what is possible across transaction boundries.
* Switch back to old context.
* ----------------
*/
MemoryContextSwitchTo(oldcontext);
/* ----------------
* Note: the "end-of-command" tag is returned by higher-level
* utility code
* ----------------
*/
MemoryContextSwitchTo(
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
}
/* --------------------------------
@ -225,15 +204,10 @@ PerformPortalClose(char *name, CommandDest dest)
*/
if (name == NULL)
{
elog(NOTICE, "PerformPortalClose: blank portal unsupported");
elog(NOTICE, "PerformPortalClose: missing portal name");
return;
}
if (PortalNameIsSpecial(name))
elog(ERROR,
"The portal name \"%s\" is reserved for internal use",
name);
/* ----------------
* get the portal from the portal name
* ----------------

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.31 2000/06/17 23:41:36 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.32 2000/06/28 03:31:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -39,7 +39,6 @@
#include "utils/fmgroids.h"
#include "utils/syscache.h"
#include "miscadmin.h" /* ReindexDatabase() */
#include "utils/portal.h" /* ReindexDatabase() */
#include "catalog/catalog.h" /* ReindexDatabase() */
#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
@ -764,7 +763,6 @@ ReindexTable(const char *name, bool force)
* "ERROR" if table nonexistent.
* ...
*/
extern Oid MyDatabaseId;
void
ReindexDatabase(const char *dbname, bool force, bool all)
{
@ -780,7 +778,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
Oid db_id;
char *username;
ScanKeyData scankey;
PortalVariableMemory pmem;
MemoryContext private_context;
MemoryContext old;
int relcnt,
relalc,
@ -808,16 +806,34 @@ ReindexDatabase(const char *dbname, bool force, bool all)
db_id = dbtuple->t_data->t_oid;
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
heap_endscan(scan);
heap_close(relation, NoLock);
if (user_id != db_owner && !superuser)
elog(ERROR, "REINDEX DATABASE: Permission denied.");
if (db_id != MyDatabaseId)
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
heap_close(relation, NoLock);
/*
* We cannot run inside a user transaction block; if we were
* inside a transaction, then our commit- and
* start-transaction-command calls would not have the intended effect!
*/
if (IsTransactionBlock())
elog(ERROR, "REINDEX DATABASE cannot run inside a BEGIN/END block");
/*
* Create a memory context that will survive forced transaction commits
* we do below. Since it is a child of QueryContext, it will go away
* eventually even if we suffer an error; there's no need for special
* abort cleanup logic.
*/
private_context = AllocSetContextCreate(QueryContext,
"ReindexDatabase",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
CommonSpecialPortalOpen();
pmem = CommonSpecialPortalGetMemory();
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL);
relcnt = relalc = 0;
@ -832,7 +848,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
}
if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
{
old = MemoryContextSwitchTo((MemoryContext) pmem);
old = MemoryContextSwitchTo(private_context);
if (relcnt == 0)
{
relalc = oncealc;
@ -859,6 +875,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
elog(NOTICE, "relation %d was reindexed", relids[i]);
CommitTransactionCommand();
}
CommonSpecialPortalClose();
StartTransactionCommand();
MemoryContextDelete(private_context);
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.69 2000/06/08 22:37:01 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.70 2000/06/28 03:31:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1029,8 +1029,8 @@ ltrmark:;
* end.
* ----------
*/
static GlobalMemory deftrig_gcxt = NULL;
static GlobalMemory deftrig_cxt = NULL;
static MemoryContext deftrig_gcxt = NULL;
static MemoryContext deftrig_cxt = NULL;
/* ----------
* Global data that tells which triggers are actually in
@ -1104,7 +1104,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
* as the current and return that.
* ----------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
trigstate = (DeferredTriggerStatus)
palloc(sizeof(DeferredTriggerStatusData));
@ -1366,7 +1366,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
int
DeferredTriggerInit(void)
{
deftrig_gcxt = CreateGlobalMemory("DeferredTriggerSession");
deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
"DeferredTriggerSession",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
return 0;
}
@ -1395,8 +1400,12 @@ DeferredTriggerBeginXact(void)
* from the per session context to here.
* ----------
*/
deftrig_cxt = CreateGlobalMemory("DeferredTriggerXact");
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
"DeferredTriggerXact",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
deftrig_all_isset = deftrig_dfl_all_isset;
deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
@ -1461,7 +1470,7 @@ DeferredTriggerEndXact(void)
deferredTriggerInvokeEvents(false);
GlobalMemoryDestroy(deftrig_cxt);
MemoryContextDelete(deftrig_cxt);
deftrig_cxt = NULL;
}
@ -1484,7 +1493,7 @@ DeferredTriggerAbortXact(void)
if (deftrig_cxt == NULL)
return;
GlobalMemoryDestroy(deftrig_cxt);
MemoryContextDelete(deftrig_cxt);
deftrig_cxt = NULL;
}
@ -1521,7 +1530,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ... outside of a transaction block
* ----------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
/* ----------
* Drop all information about individual trigger states per
@ -1555,7 +1564,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* ... inside of a transaction block
* ----------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
/* ----------
* Drop all information about individual trigger states per
@ -1701,7 +1710,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* states of individual triggers on session level.
* ----------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
foreach(l, loid)
{
@ -1739,7 +1748,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
* states of individual triggers on transaction level.
* ----------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
foreach(l, loid)
{
@ -1827,7 +1836,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
* Create a new event
* ----------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
ntriggers = rel->trigdesc->n_after_row[event];
triggers = rel->trigdesc->tg_after_row[event];
@ -2022,7 +2031,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
* Anything's fine up to here. Add the new event to the queue.
* ----------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
deferredTriggerAddEvent(new_event);
MemoryContextSwitchTo(oldcxt);

View File

@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* user.c
* use pg_exec_query to create a new user in the catalog
* Commands for manipulating users and groups.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.61 2000/06/25 14:24:59 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.62 2000/06/28 03:31:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.161 2000/06/28 03:31:28 tgl Exp $
*
*-------------------------------------------------------------------------
@ -35,7 +35,6 @@
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/portal.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
#include "utils/temprel.h"
@ -48,9 +47,7 @@
#endif
bool CommonSpecialPortalInUse = false;
static Portal vac_portal;
static MemoryContext vac_context = NULL;
static int MESSAGE_LEVEL; /* message level */
@ -82,14 +79,13 @@ static int vac_cmp_offno(const void *left, const void *right);
static int vac_cmp_vtlinks(const void *left, const void *right);
static bool enough_space(VacPage vacpage, Size len);
static char *show_rusage(struct rusage * ru0);
/* CommonSpecialPortal function at the bottom */
void
vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
{
NameData VacRel;
Name VacRelName;
PortalVariableMemory pmem;
MemoryContext old;
List *le;
List *anal_cols2 = NIL;
@ -114,8 +110,18 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
else
MESSAGE_LEVEL = DEBUG;
/* Create special portal for cross-transaction storage */
CommonSpecialPortalOpen();
/*
* Create special memory context for cross-transaction storage.
*
* Since it is a child of QueryContext, it will go away eventually
* even if we suffer an error; there's no need for special abort
* cleanup logic.
*/
vac_context = AllocSetContextCreate(QueryContext,
"Vacuum",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* vacrel gets de-allocated on xact commit, so copy it to safe storage */
if (vacrel)
@ -127,8 +133,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
VacRelName = NULL;
/* must also copy the column list, if any, to safe storage */
pmem = CommonSpecialPortalGetMemory();
old = MemoryContextSwitchTo((MemoryContext) pmem);
old = MemoryContextSwitchTo(vac_context);
foreach(le, anal_cols)
{
char *col = (char *) lfirst(le);
@ -198,11 +203,16 @@ vacuum_shutdown()
*/
unlink(RELCACHE_INIT_FILENAME);
/* Clean up working storage */
CommonSpecialPortalClose();
/* matches the CommitTransaction in PostgresMain() */
StartTransactionCommand();
/*
* Clean up working storage --- note we must do this after
* StartTransactionCommand, else we might be trying to delete
* the active context!
*/
MemoryContextDelete(vac_context);
vac_context = NULL;
}
/*
@ -239,8 +249,6 @@ getrels(NameData *VacRelP)
TupleDesc tupdesc;
HeapScanDesc scan;
HeapTuple tuple;
PortalVariableMemory portalmem;
MemoryContext old;
VRelList vrl,
cur;
Datum d;
@ -276,7 +284,6 @@ getrels(NameData *VacRelP)
F_CHAREQ, CharGetDatum('r'));
}
portalmem = CommonSpecialPortalGetMemory();
vrl = cur = (VRelList) NULL;
rel = heap_openr(RelationRelationName, AccessShareLock);
@ -302,25 +309,26 @@ getrels(NameData *VacRelP)
}
/* get a relation list entry for this guy */
old = MemoryContextSwitchTo((MemoryContext) portalmem);
if (vrl == (VRelList) NULL)
vrl = cur = (VRelList) palloc(sizeof(VRelListData));
vrl = cur = (VRelList)
MemoryContextAlloc(vac_context, sizeof(VRelListData));
else
{
cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
cur->vrl_next = (VRelList)
MemoryContextAlloc(vac_context, sizeof(VRelListData));
cur = cur->vrl_next;
}
MemoryContextSwitchTo(old);
cur->vrl_relid = tuple->t_data->t_oid;
cur->vrl_next = (VRelList) NULL;
}
if (found == false)
elog(NOTICE, "Vacuum: table not found");
heap_endscan(scan);
heap_close(rel, AccessShareLock);
if (!found)
elog(NOTICE, "Vacuum: table not found");
CommitTransactionCommand();
return vrl;
@ -2275,62 +2283,6 @@ vac_cmp_vtlinks(const void *left, const void *right)
}
/*
* This routines handle a special cross-transaction portal.
* However it is automatically closed in case of abort.
*/
void
CommonSpecialPortalOpen(void)
{
char *pname;
if (CommonSpecialPortalInUse)
elog(ERROR, "CommonSpecialPortal is in use");
/*
* Create a portal for safe memory across transactions. We need to
* palloc the name space for it because our hash function expects the
* name to be on a longword boundary. CreatePortal copies the name to
* safe storage for us.
*/
pname = pstrdup(VACPNAME);
vac_portal = CreatePortal(pname);
pfree(pname);
/*
* Set flag to indicate that vac_portal must be removed after an error.
* This global variable is checked in the transaction manager on xact
* abort, and the routine CommonSpecialPortalClose() is called if
* necessary.
*/
CommonSpecialPortalInUse = true;
}
void
CommonSpecialPortalClose(void)
{
/* Clear flag first, to avoid recursion if PortalDrop elog's */
CommonSpecialPortalInUse = false;
/*
* Release our portal for cross-transaction memory.
*/
PortalDrop(&vac_portal);
}
PortalVariableMemory
CommonSpecialPortalGetMemory(void)
{
return PortalGetVariableMemory(vac_portal);
}
bool
CommonSpecialPortalIsOpen(void)
{
return CommonSpecialPortalInUse;
}
static void
get_indices(Relation relation, int *nindices, Relation **Irel)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.34 2000/05/28 17:55:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.35 2000/06/28 03:31:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -87,8 +87,8 @@ init_execution_state(FunctionCachePtr fcache)
nextes = newes;
preves = (execution_state *) NULL;
queryTree_list = pg_parse_and_rewrite(fcache->src, fcache->argOidVect,
nargs, FALSE);
queryTree_list = pg_parse_and_rewrite(fcache->src,
fcache->argOidVect, nargs);
foreach(qtl_item, queryTree_list)
{

View File

@ -32,7 +32,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.67 2000/06/15 03:32:09 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.68 2000/06/28 03:31:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -265,7 +265,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
else
newVal = FunctionCallInvoke(&fcinfo);
if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
pfree(peraggstate->value1);
pfree(DatumGetPointer(peraggstate->value1));
peraggstate->value1 = newVal;
peraggstate->value1IsNull = fcinfo.isnull;
}
@ -288,7 +288,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
else
newVal = FunctionCallInvoke(&fcinfo);
if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
pfree(peraggstate->value2);
pfree(DatumGetPointer(peraggstate->value2));
peraggstate->value2 = newVal;
peraggstate->value2IsNull = fcinfo.isnull;
}
@ -424,12 +424,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
if (OidIsValid(peraggstate->xfn1_oid) &&
!peraggstate->value1IsNull &&
!peraggstate->transtype1ByVal)
pfree(peraggstate->value1);
pfree(DatumGetPointer(peraggstate->value1));
if (OidIsValid(peraggstate->xfn2_oid) &&
!peraggstate->value2IsNull &&
!peraggstate->transtype2ByVal)
pfree(peraggstate->value2);
pfree(DatumGetPointer(peraggstate->value2));
}
/* ---------------------------------------

View File

@ -7,14 +7,14 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: nodeHash.c,v 1.47 2000/06/15 04:09:52 momjian Exp $
* $Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecHash - generate an in-memory hash table of the relation
* ExecInitHash - initialize node and subnodes..
* ExecInitHash - initialize node and subnodes
* ExecEndHash - shutdown node and subnodes
*
*/
@ -23,11 +23,12 @@
#include <math.h>
#include "postgres.h"
#include "executor/execdebug.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "miscadmin.h"
#include "utils/portal.h"
static int hashFunc(Datum key, int len, bool byVal);
@ -235,8 +236,6 @@ ExecHashTableCreate(Hash *node)
int totalbuckets;
int bucketsize;
int i;
Portal myPortal;
char myPortalName[64];
MemoryContext oldcxt;
/* ----------------
@ -348,23 +347,21 @@ ExecHashTableCreate(Hash *node)
hashtable->outerBatchSize = NULL;
/* ----------------
* Create a named portal in which to keep the hashtable working storage.
* Each hashjoin must have its own portal, so be wary of name conflicts.
* Create temporary memory contexts in which to keep the hashtable
* working storage. See notes in executor/hashjoin.h.
* ----------------
*/
i = 0;
do
{
i++;
sprintf(myPortalName, "<hashtable %d>", i);
myPortal = GetPortalByName(myPortalName);
} while (PortalIsValid(myPortal));
myPortal = CreatePortal(myPortalName);
Assert(PortalIsValid(myPortal));
hashtable->myPortal = (void *) myPortal; /* kluge for circular
* includes */
hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
"HashTableContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
"HashBatchContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* Allocate data that will live for the life of the hashjoin */
@ -395,11 +392,10 @@ ExecHashTableCreate(Hash *node)
}
/*
* Prepare portal for the first-scan space allocations; allocate the
* Prepare context for the first-scan space allocations; allocate the
* hashbucket array therein, and set each bucket "empty".
*/
MemoryContextSwitchTo(hashtable->batchCxt);
StartPortalAllocMode(DefaultAllocMode, 0);
hashtable->buckets = (HashJoinTuple *)
palloc(nbuckets * sizeof(HashJoinTuple));
@ -435,9 +431,8 @@ ExecHashTableDestroy(HashJoinTable hashtable)
BufFileClose(hashtable->outerBatchFile[i]);
}
/* Destroy the portal to release all working memory */
/* cast here is a kluge for circular includes... */
PortalDrop((Portal *) &hashtable->myPortal);
/* Release working memory (batchCxt is a child, so it goes away too) */
MemoryContextDelete(hashtable->hashCxt);
/* And drop the control block */
pfree(hashtable);
@ -676,11 +671,10 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
/*
* Release all the hash buckets and tuples acquired in the prior pass,
* and reinitialize the portal for a new pass.
* and reinitialize the context for a new pass.
*/
MemoryContextReset(hashtable->batchCxt);
oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
EndPortalAllocMode();
StartPortalAllocMode(DefaultAllocMode, 0);
/*
* We still use the same number of physical buckets as in the first

View File

@ -3,21 +3,20 @@
* spi.c
* Server Programming Interface
*
* $Id: spi.c,v 1.46 2000/05/30 04:24:45 tgl Exp $
* $Id: spi.c,v 1.47 2000/06/28 03:31:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "executor/spi_priv.h"
#include "access/printtup.h"
static Portal _SPI_portal = (Portal) NULL;
static _SPI_connection *_SPI_stack = NULL;
static _SPI_connection *_SPI_current = NULL;
static int _SPI_connected = -1;
static int _SPI_curid = -1;
DLLIMPORT uint32 SPI_processed = 0;
DLLIMPORT SPITupleTable *SPI_tuptable;
DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
DLLIMPORT int SPI_result;
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
@ -46,28 +45,6 @@ extern void ShowUsage(void);
int
SPI_connect()
{
char pname[64];
PortalVariableMemory pvmem;
/*
* It's possible on startup and after commit/abort. In future we'll
* catch commit/abort in some way...
*/
strcpy(pname, "<SPI manager>");
_SPI_portal = GetPortalByName(pname);
if (!PortalIsValid(_SPI_portal))
{
if (_SPI_stack != NULL) /* there was abort */
free(_SPI_stack);
_SPI_current = _SPI_stack = NULL;
_SPI_connected = _SPI_curid = -1;
SPI_processed = 0;
SPI_tuptable = NULL;
_SPI_portal = CreatePortal(pname);
if (!PortalIsValid(_SPI_portal))
elog(FATAL, "SPI_connect: global initialization failed");
}
/*
* When procedure called by Executor _SPI_curid expected to be equal
* to _SPI_connected
@ -99,15 +76,19 @@ SPI_connect()
_SPI_current->processed = 0;
_SPI_current->tuptable = NULL;
/* Create Portal for this procedure ... */
snprintf(pname, 64, "<SPI %d>", _SPI_connected);
_SPI_current->portal = CreatePortal(pname);
if (!PortalIsValid(_SPI_current->portal))
elog(FATAL, "SPI_connect: initialization failed");
/* ... and switch to Portal' Variable memory - procedure' context */
pvmem = PortalGetVariableMemory(_SPI_current->portal);
_SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
/* Create memory contexts for this procedure */
_SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
"SPI Proc",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
_SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
"SPI Exec",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* ... and switch to procedure's context */
_SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
_SPI_current->savedId = GetScanCommandId();
SetScanCommandId(GetCurrentCommandId());
@ -127,7 +108,10 @@ SPI_finish()
/* Restore memory context as it was before procedure call */
MemoryContextSwitchTo(_SPI_current->savedcxt);
PortalDrop(&(_SPI_current->portal));
/* Release memory used in procedure call */
MemoryContextDelete(_SPI_current->execCxt);
MemoryContextDelete(_SPI_current->procCxt);
SetScanCommandId(_SPI_current->savedId);
@ -142,6 +126,7 @@ SPI_finish()
{
free(_SPI_stack);
_SPI_stack = NULL;
_SPI_current = NULL;
}
else
{
@ -154,6 +139,25 @@ SPI_finish()
}
/*
* Clean up SPI state at transaction commit or abort (we don't care which).
*/
void
AtEOXact_SPI(void)
{
/*
* Note that memory contexts belonging to SPI stack entries will be
* freed automatically, so we can ignore them here. We just need to
* restore our static variables to initial state.
*/
if (_SPI_stack != NULL) /* there was abort */
free(_SPI_stack);
_SPI_current = _SPI_stack = NULL;
_SPI_connected = _SPI_curid = -1;
SPI_processed = 0;
SPI_tuptable = NULL;
}
void
SPI_push(void)
{
@ -508,61 +512,22 @@ SPI_palloc(Size size)
void *
SPI_repalloc(void *pointer, Size size)
{
MemoryContext oldcxt = NULL;
if (_SPI_curid + 1 == _SPI_connected) /* connected */
{
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
elog(FATAL, "SPI: stack corrupted");
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
}
pointer = repalloc(pointer, size);
if (oldcxt)
MemoryContextSwitchTo(oldcxt);
return pointer;
/* No longer need to worry which context chunk was in... */
return repalloc(pointer, size);
}
void
SPI_pfree(void *pointer)
{
MemoryContext oldcxt = NULL;
if (_SPI_curid + 1 == _SPI_connected) /* connected */
{
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
elog(FATAL, "SPI: stack corrupted");
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
}
/* No longer need to worry which context chunk was in... */
pfree(pointer);
if (oldcxt)
MemoryContextSwitchTo(oldcxt);
return;
}
void
SPI_freetuple(HeapTuple tuple)
{
MemoryContext oldcxt = NULL;
if (_SPI_curid + 1 == _SPI_connected) /* connected */
{
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
elog(FATAL, "SPI: stack corrupted");
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
}
/* No longer need to worry which context tuple was in... */
heap_freetuple(tuple);
if (oldcxt)
MemoryContextSwitchTo(oldcxt);
return;
}
/* =================== private functions =================== */
@ -647,7 +612,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
argtypes = plan->argtypes;
}
queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs, FALSE);
queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
_SPI_current->qtlist = queryTree_list;
@ -790,7 +755,6 @@ static int
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
{
Query *parseTree = queryDesc->parsetree;
Plan *plan = queryDesc->plantree;
int operation = queryDesc->operation;
CommandDest dest = queryDesc->dest;
TupleDesc tupdesc;
@ -875,16 +839,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
#endif
tupdesc = ExecutorStart(queryDesc, state);
/* Don't work currently */
/* Don't work currently --- need to rearrange callers so that
* we prepare the portal before doing CreateExecutorState() etc.
* See pquery.c for the correct order of operations.
*/
if (isRetrieveIntoPortal)
{
ProcessPortal(intoName,
parseTree,
plan,
state,
tupdesc,
None);
return SPI_OK_CURSOR;
elog(FATAL, "SPI_select: retrieve into portal not implemented");
}
ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
@ -920,27 +881,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
static MemoryContext
_SPI_execmem()
{
MemoryContext oldcxt;
PortalHeapMemory phmem;
phmem = PortalGetHeapMemory(_SPI_current->portal);
oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
return oldcxt;
return MemoryContextSwitchTo(_SPI_current->execCxt);
}
static MemoryContext
_SPI_procmem()
{
MemoryContext oldcxt;
PortalVariableMemory pvmem;
pvmem = PortalGetVariableMemory(_SPI_current->portal);
oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
return oldcxt;
return MemoryContextSwitchTo(_SPI_current->procCxt);
}
/*
@ -959,7 +906,6 @@ _SPI_begin_call(bool execmem)
if (execmem) /* switch to the Executor memory context */
{
_SPI_execmem();
StartPortalAllocMode(DefaultAllocMode, 0);
}
return 0;
@ -977,9 +923,10 @@ _SPI_end_call(bool procmem)
_SPI_current->qtlist = NULL;
if (procmem) /* switch to the procedure memory context */
{ /* but free Executor memory before */
EndPortalAllocMode();
{
_SPI_procmem();
/* and free Executor memory */
MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
}
return 0;
@ -1016,8 +963,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
MemoryContext oldcxt = NULL;
if (location == _SPI_CPLAN_PROCXT)
oldcxt = MemoryContextSwitchTo((MemoryContext)
PortalGetVariableMemory(_SPI_current->portal));
oldcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
else if (location == _SPI_CPLAN_TOPCXT)
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
@ -1033,7 +979,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
else
newplan->argtypes = NULL;
if (location != _SPI_CPLAN_CURCXT)
if (oldcxt != NULL)
MemoryContextSwitchTo(oldcxt);
return newplan;

View File

@ -4,14 +4,14 @@
# Makefile for lib (miscellaneous stuff)
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.13 2000/05/29 05:44:45 tgl Exp $
# $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.14 2000/06/28 03:31:34 tgl Exp $
#
#-------------------------------------------------------------------------
SRCDIR = ../..
include ../../Makefile.global
OBJS = bit.o fstack.o hasht.o lispsort.o stringinfo.o dllist.o
OBJS = bit.o hasht.o lispsort.o stringinfo.o dllist.o
all: SUBSYS.o

View File

@ -1,145 +0,0 @@
/*-------------------------------------------------------------------------
*
* fstack.c
* Fixed format stack definitions.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.14 2000/01/26 05:56:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "lib/fstack.h"
/*
* Internal function definitions
*/
/*
* FixedItemIsValid
* True iff item is valid.
*/
#define FixedItemIsValid(item) PointerIsValid(item)
/*
* FixedStackGetItemBase
* Returns base of enclosing structure.
*/
#define FixedStackGetItemBase(stack, item) \
((Pointer)((char *)(item) - (stack)->offset))
/*
* FixedStackGetItem
* Returns item of given pointer to enclosing structure.
*/
#define FixedStackGetItem(stack, pointer) \
((FixedItem)((char *)(pointer) + (stack)->offset))
#define FixedStackIsValid(stack) ((bool)PointerIsValid(stack))
/*
* External functions
*/
void
FixedStackInit(FixedStack stack, Offset offset)
{
AssertArg(PointerIsValid(stack));
stack->top = NULL;
stack->offset = offset;
}
Pointer
FixedStackPop(FixedStack stack)
{
Pointer pointer;
AssertArg(FixedStackIsValid(stack));
if (!PointerIsValid(stack->top))
return NULL;
pointer = FixedStackGetItemBase(stack, stack->top);
stack->top = stack->top->next;
return pointer;
}
void
FixedStackPush(FixedStack stack, Pointer pointer)
{
FixedItem item = FixedStackGetItem(stack, pointer);
AssertArg(FixedStackIsValid(stack));
AssertArg(PointerIsValid(pointer));
item->next = stack->top;
stack->top = item;
}
#ifdef USE_ASSERT_CHECKING
/*
* FixedStackContains
* True iff ordered stack contains given element.
*
* Note:
* This is inefficient. It is intended for debugging use only.
*
* Exceptions:
* BadArg if stack is invalid.
* BadArg if pointer is invalid.
*/
static bool
FixedStackContains(FixedStack stack, Pointer pointer)
{
FixedItem next;
FixedItem item;
AssertArg(FixedStackIsValid(stack));
AssertArg(PointerIsValid(pointer));
item = FixedStackGetItem(stack, pointer);
for (next = stack->top; FixedItemIsValid(next); next = next->next)
{
if (next == item)
return true;
}
return false;
}
#endif
Pointer
FixedStackGetTop(FixedStack stack)
{
AssertArg(FixedStackIsValid(stack));
if (!PointerIsValid(stack->top))
return NULL;
return FixedStackGetItemBase(stack, stack->top);
}
Pointer
FixedStackGetNext(FixedStack stack, Pointer pointer)
{
FixedItem item;
/* AssertArg(FixedStackIsValid(stack)); */
/* AssertArg(PointerIsValid(pointer)); */
AssertArg(FixedStackContains(stack, pointer));
item = FixedStackGetItem(stack, pointer)->next;
if (!PointerIsValid(item))
return NULL;
return FixedStackGetItemBase(stack, item);
}

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: stringinfo.c,v 1.25 2000/04/12 17:15:11 momjian Exp $
* $Id: stringinfo.c,v 1.26 2000/06/28 03:31:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -29,8 +29,6 @@ makeStringInfo(void)
StringInfo res;
res = (StringInfo) palloc(sizeof(StringInfoData));
if (res == NULL)
elog(ERROR, "makeStringInfo: Out of memory");
initStringInfo(res);
@ -49,9 +47,6 @@ initStringInfo(StringInfo str)
int size = 256; /* initial default buffer size */
str->data = (char *) palloc(size);
if (str->data == NULL)
elog(ERROR,
"initStringInfo: Out of memory (%d bytes requested)", size);
str->maxlen = size;
str->len = 0;
str->data[0] = '\0';
@ -62,6 +57,11 @@ initStringInfo(StringInfo str)
*
* Internal routine: make sure there is enough space for 'needed' more bytes
* ('needed' does not include the terminating null).
*
* NB: because we use repalloc() to enlarge the buffer, the string buffer
* will remain allocated in the same memory context that was current when
* initStringInfo was called, even if another context is now current.
* This is the desired and indeed critical behavior!
*/
static void
enlargeStringInfo(StringInfo str, int needed)
@ -83,9 +83,6 @@ enlargeStringInfo(StringInfo str, int needed)
newlen = 2 * newlen;
str->data = (char *) repalloc(str->data, newlen);
if (str->data == NULL)
elog(ERROR,
"enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
str->maxlen = newlen;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.46 2000/06/09 01:11:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.47 2000/06/28 03:31:41 tgl Exp $
*
* NOTES
* This should be moved to a more appropriate place. It is here
@ -16,7 +16,7 @@
*
* Builtin functions for open/close/read/write operations on large objects.
*
* These functions operate in a private GlobalMemoryContext, which means
* These functions operate in a private MemoryContext, which means
* that large object descriptors hang around until we destroy the context.
* That happens in lo_commit(). It'd be possible to prolong the lifetime
* of the context so that LO FDs are good across transactions (for example,
@ -24,8 +24,10 @@
* But we'd need additional state in order to do the right thing at the
* end of an aborted transaction. FDs opened during an aborted xact would
* still need to be closed, since they might not be pointing at valid
* relations at all. For now, we'll stick with the existing documented
* semantics of LO FDs: they're only good within a transaction.
* relations at all. Locking semantics are also an interesting problem
* if LOs stay open across transactions. For now, we'll stick with the
* existing documented semantics of LO FDs: they're only good within a
* transaction.
*
*-------------------------------------------------------------------------
*/
@ -56,7 +58,7 @@
*/
static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
static GlobalMemory fscxt = NULL;
static MemoryContext fscxt = NULL;
static int newLOfd(LargeObjectDesc *lobjCookie);
@ -80,8 +82,13 @@ lo_open(PG_FUNCTION_ARGS)
#endif
if (fscxt == NULL)
fscxt = CreateGlobalMemory("Filesystem");
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
fscxt = AllocSetContextCreate(TopMemoryContext,
"Filesystem",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
currentContext = MemoryContextSwitchTo(fscxt);
lobjDesc = inv_open(lobjId, mode);
@ -128,7 +135,7 @@ lo_close(PG_FUNCTION_ARGS)
#endif
Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
currentContext = MemoryContextSwitchTo(fscxt);
inv_close(cookies[fd]);
@ -166,7 +173,7 @@ lo_read(int fd, char *buf, int len)
}
Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
currentContext = MemoryContextSwitchTo(fscxt);
status = inv_read(cookies[fd], buf, len);
@ -193,7 +200,7 @@ lo_write(int fd, char *buf, int len)
}
Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
currentContext = MemoryContextSwitchTo(fscxt);
status = inv_write(cookies[fd], buf, len);
@ -224,7 +231,7 @@ lo_lseek(PG_FUNCTION_ARGS)
}
Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
currentContext = MemoryContextSwitchTo(fscxt);
status = inv_seek(cookies[fd], offset, whence);
@ -242,9 +249,13 @@ lo_creat(PG_FUNCTION_ARGS)
Oid lobjId;
if (fscxt == NULL)
fscxt = CreateGlobalMemory("Filesystem");
fscxt = AllocSetContextCreate(TopMemoryContext,
"Filesystem",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
currentContext = MemoryContextSwitchTo(fscxt);
lobjDesc = inv_create(mode);
@ -493,7 +504,7 @@ lo_commit(bool isCommit)
if (fscxt == NULL)
return; /* no LO operations in this xact */
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
currentContext = MemoryContextSwitchTo(fscxt);
/*
* Clean out still-open index scans (not necessary if aborting) and
@ -512,7 +523,7 @@ lo_commit(bool isCommit)
MemoryContextSwitchTo(currentContext);
/* Release the LO memory context to prevent permanent memory leaks. */
GlobalMemoryDestroy(fscxt);
MemoryContextDelete(fscxt);
fscxt = NULL;
}

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.32 2000/05/28 17:55:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.33 2000/06/28 03:31:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -135,9 +135,11 @@ PQexec(char *query)
/* ----------------
* pg_exec_query_dest will put the query results in a portal which will
* end up on the top of the portal stack.
*
* XXX memory context manipulation needs thought here.
* ----------------
*/
pg_exec_query_dest(query, Local, FALSE);
pg_exec_query_dest(query, Local, CurrentMemoryContext);
/* ----------------
* pop the portal off the portal stack and return the

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.15 2000/06/11 11:39:50 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.16 2000/06/28 03:31:41 tgl Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
@ -44,6 +44,44 @@
#include "libpq/pqsignal.h"
/*
* Initialize BlockSig and UnBlockSig.
*
* BlockSig is the set of signals to block when we are trying to block
* signals. This includes all signals we normally expect to get, but NOT
* signals that should never be turned off.
*
* UnBlockSig is the set of signals to block when we don't want to block
* signals (is this ever nonzero??)
*/
void
pqinitmask(void)
{
#ifdef HAVE_SIGPROCMASK
sigemptyset(&UnBlockSig);
sigfillset(&BlockSig);
sigdelset(&BlockSig, SIGABRT);
sigdelset(&BlockSig, SIGILL);
sigdelset(&BlockSig, SIGSEGV);
sigdelset(&BlockSig, SIGBUS);
sigdelset(&BlockSig, SIGTRAP);
sigdelset(&BlockSig, SIGCONT);
sigdelset(&BlockSig, SIGSYS);
#else
UnBlockSig = 0;
BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) |
sigmask(SIGTERM) | sigmask(SIGALRM) |
sigmask(SIGINT) | sigmask(SIGUSR1) |
sigmask(SIGUSR2) | sigmask(SIGCHLD) |
sigmask(SIGWINCH) | sigmask(SIGFPE);
#endif
}
/*
* Set up a signal handler
*/
pqsigfunc
pqsignal(int signo, pqsigfunc func)
{

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: geqo_eval.c,v 1.50 2000/05/30 00:49:46 momjian Exp $
* $Id: geqo_eval.c,v 1.51 2000/06/28 03:31:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -19,9 +19,9 @@
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
#include <math.h>
#include "postgres.h"
#include <math.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#else
@ -33,42 +33,9 @@
#include "optimizer/geqo.h"
#include "optimizer/pathnode.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
*
@ -77,21 +44,31 @@ geqo_eval_startup(void)
Cost
geqo_eval(Query *root, Gene *tour, int num_gene)
{
MemoryContext mycontext;
MemoryContext oldcxt;
RelOptInfo *joinrel;
Cost fitness;
List *savelist;
/*
* Create a private memory context that will hold all temp storage
* allocated inside gimme_tree().
*
* Since geqo_eval() will be called many times, we can't afford to let
* all that memory go unreclaimed until end of statement. Note we make
* the temp context a child of TransactionCommandContext, so that
* it will be freed even if we abort via elog(ERROR).
*/
mycontext = AllocSetContextCreate(TransactionCommandContext,
"GEQO",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(mycontext);
/* preserve root->join_rel_list, which gimme_tree changes */
savelist = root->join_rel_list;
/*
* create a temporary allocation context for the path construction
* work
*/
oldcxt = MemoryContextSwitchTo(geqo_eval_context);
StartPortalAllocMode(DefaultAllocMode, 0);
/* construct the best path for the given combination of relations */
joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
@ -107,8 +84,8 @@ geqo_eval(Query *root, Gene *tour, int num_gene)
root->join_rel_list = savelist;
/* release all the memory acquired within gimme_tree */
EndPortalAllocMode();
MemoryContextSwitchTo(oldcxt);
MemoryContextDelete(mycontext);
return fitness;
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: geqo_main.c,v 1.21 2000/05/31 00:28:19 petere Exp $
* $Id: geqo_main.c,v 1.22 2000/06/28 03:31:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -110,9 +110,6 @@ geqo(Query *root)
else
srandom(time(NULL));
/* initialize plan evaluator */
geqo_eval_startup();
/* allocate genetic pool memory */
pool = alloc_pool(pool_size, number_of_rels);

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.149 2000/06/22 22:31:20 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.150 2000/06/28 03:31:52 tgl Exp $
*
* NOTES
*
@ -378,15 +378,38 @@ PostmasterMain(int argc, char *argv[])
*/
umask((mode_t) 0077);
ResetAllOptions();
MyProcPid = getpid();
/*
* Fire up essential subsystems: error and memory management
*/
EnableExceptionHandling(true);
MemoryContextInit();
/*
* By default, palloc() requests in the postmaster will be allocated
* in the PostmasterContext, which is space that can be recycled by
* backends. Allocated data that needs to be available to backends
* should be allocated in TopMemoryContext.
*/
PostmasterContext = AllocSetContextCreate(TopMemoryContext,
"Postmaster",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
MemoryContextSwitchTo(PostmasterContext);
/*
* Options setup
*/
if (getenv("PGDATA"))
DataDir = strdup(getenv("PGDATA")); /* default value */
if (getenv("PGPORT"))
PostPortName = atoi(getenv("PGPORT"));
ResetAllOptions();
/*
* First we must scan for a -D argument to get the data dir. Then
* read the config file. Finally, scan all the other arguments.
@ -600,7 +623,6 @@ PostmasterMain(int argc, char *argv[])
}
#endif
/* set up shared memory and semaphores */
EnableMemoryContext(TRUE);
reset_shared(PostPortName);
/*
@ -662,7 +684,7 @@ PostmasterMain(int argc, char *argv[])
/*
* Set up signal handlers for the postmaster process.
*/
PG_INITMASK();
pqinitmask();
PG_SETMASK(&BlockSig);
pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have children do same */
@ -1867,6 +1889,7 @@ DoBackend(Port *port)
/* Save port etc. for ps status */
MyProcPort = port;
/* Reset MyProcPid to new backend's pid */
MyProcPid = getpid();
/*
@ -1946,6 +1969,19 @@ DoBackend(Port *port)
av[ac] = (char *) NULL;
/*
* Release postmaster's working memory context so that backend can
* recycle the space. Note we couldn't do it earlier than here,
* because port pointer is pointing into that space! But now we
* have copied all the interesting info into safe local storage.
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextDelete(PostmasterContext);
PostmasterContext = NULL;
/*
* Debug: print arguments being passed to backend
*/
if (DebugLvl > 1)
{
fprintf(stderr, "%s child[%d]: starting with (",

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.46 2000/06/15 04:09:58 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.47 2000/06/28 03:31:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,51 +16,20 @@
#include "postgres.h"
#include "access/heapam.h"
#include "lib/stringinfo.h"
#include "utils/builtins.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_rewrite.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteSupport.h"
#include "tcop/tcopprot.h"
Oid LastOidProcessed = InvalidOid;
/*
* Convert given string to a suitably quoted string constant,
* and append it to the StringInfo buffer.
* XXX Any MULTIBYTE considerations here?
*/
static void
quoteString(StringInfo buf, char *source)
{
char *current;
appendStringInfoChar(buf, '\'');
for (current = source; *current; current++)
{
char ch = *current;
if (ch == '\'' || ch == '\\')
{
appendStringInfoChar(buf, '\\');
appendStringInfoChar(buf, ch);
}
else if (ch >= 0 && ch < ' ')
appendStringInfo(buf, "\\%03o", (int) ch);
else
appendStringInfoChar(buf, ch);
}
appendStringInfoChar(buf, '\'');
}
/*
* InsertRule -
* takes the arguments and inserts them as attributes into the system
* relation "pg_rewrite"
*
* MODS : changes the value of LastOidProcessed as a side
* effect of inserting the rule tuple
*
* ARGS : rulname - name of the rule
* evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
* evobj - name of relation
@ -78,11 +47,17 @@ InsertRule(char *rulname,
bool evinstead,
char *actiontree)
{
StringInfoData rulebuf;
Relation eventrel;
Oid eventrel_oid;
AttrNumber evslot_index;
char *is_instead = "f";
int i;
Datum values[Natts_pg_rewrite];
char nulls[Natts_pg_rewrite];
NameData rname;
Relation pg_rewrite_desc;
TupleDesc tupDesc;
HeapTuple tup;
Oid rewriteObjectId;
eventrel = heap_openr(evobj, AccessShareLock);
eventrel_oid = RelationGetRelid(eventrel);
@ -96,9 +71,6 @@ InsertRule(char *rulname,
evslot_index = attnameAttNum(eventrel, evslot);
heap_close(eventrel, AccessShareLock);
if (evinstead)
is_instead = "t";
if (evqual == NULL)
evqual = "<>";
@ -106,23 +78,54 @@ InsertRule(char *rulname,
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
rulname);
initStringInfo(&rulebuf);
appendStringInfo(&rulebuf,
"INSERT INTO pg_rewrite (rulename, ev_type, ev_class, ev_attr, ev_action, ev_qual, is_instead) VALUES (");
quoteString(&rulebuf, rulname);
appendStringInfo(&rulebuf, ", %d::char, %u::oid, %d::int2, ",
evtype, eventrel_oid, evslot_index);
quoteString(&rulebuf, actiontree);
appendStringInfo(&rulebuf, "::text, ");
quoteString(&rulebuf, evqual);
appendStringInfo(&rulebuf, "::text, '%s'::bool);",
is_instead);
/* ----------------
* Set up *nulls and *values arrays
* ----------------
*/
MemSet(nulls, ' ', sizeof(nulls));
pg_exec_query_dest(rulebuf.data, None, true);
i = 0;
namestrcpy(&rname, rulname);
values[i++] = NameGetDatum(&rname);
values[i++] = CharGetDatum(evtype + '0');
values[i++] = ObjectIdGetDatum(eventrel_oid);
values[i++] = Int16GetDatum(evslot_index);
values[i++] = BoolGetDatum(evinstead);
values[i++] = PointerGetDatum(lztextin(evqual));
values[i++] = PointerGetDatum(lztextin(actiontree));
pfree(rulebuf.data);
/* ----------------
* create a new pg_rewrite tuple
* ----------------
*/
pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
return LastOidProcessed;
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);
}
heap_freetuple(tup);
heap_close(pg_rewrite_desc, RowExclusiveLock);
return rewriteObjectId;
}
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.41 2000/01/26 05:56:50 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.42 2000/06/28 03:31:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -136,7 +136,7 @@ prs2_addToRelation(Oid relid,
* create an in memory RewriteRule data structure which is cached by
* every Relation descriptor. (see utils/cache/relcache.c)
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
if (qual != NULL)
qual = copyObject(qual);
@ -159,7 +159,7 @@ prs2_addToRelation(Oid relid,
if (relation->rd_rules == NULL)
{
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
rulelock = (RuleLock *) palloc(sizeof(RuleLock));
rulelock->numLocks = 1;
rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
@ -181,7 +181,7 @@ prs2_addToRelation(Oid relid,
rulelock = relation->rd_rules;
numlock = rulelock->numLocks;
/* expand, for safety reasons */
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
sizeof(RewriteRule *) * (numlock + 1));
MemoryContextSwitchTo(oldcxt);
@ -212,7 +212,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
break;
}
Assert(i < numlock);
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
pfree(rulelock->rules[i]);
MemoryContextSwitchTo(oldcxt);
if (numlock == 1)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.51 2000/05/30 00:49:52 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.52 2000/06/28 03:31:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -262,29 +262,23 @@ InitShmem(unsigned int key, unsigned int size)
}
/*
* ShmemAlloc -- allocate word-aligned byte string from
* shared memory
* ShmemAlloc -- allocate max-aligned byte string from shared memory
*
* Assumes ShmemLock and ShmemFreeStart are initialized.
* Returns: real pointer to memory or NULL if we are out
* of space. Has to return a real pointer in order
* to be compatable with malloc().
* to be compatible with malloc().
*/
long *
ShmemAlloc(unsigned long size)
void *
ShmemAlloc(Size size)
{
unsigned long tmpFree;
long *newSpace;
void *newSpace;
/*
* ensure space is word aligned.
*
* Word-alignment is not good enough. We have to be more conservative:
* doubles need 8-byte alignment. (We probably only need this on RISC
* platforms but this is not a big waste of space.) - ay 12/94
* ensure all space is adequately aligned.
*/
if (size % sizeof(double))
size += sizeof(double) - (size % sizeof(double));
size = MAXALIGN(size);
Assert(*ShmemFreeStart);
@ -293,7 +287,7 @@ ShmemAlloc(unsigned long size)
tmpFree = *ShmemFreeStart + size;
if (tmpFree <= ShmemSize)
{
newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
*ShmemFreeStart += size;
}
else
@ -302,7 +296,8 @@ ShmemAlloc(unsigned long size)
SpinRelease(ShmemLock);
if (!newSpace)
elog(NOTICE, "ShmemAlloc: out of memory ");
elog(NOTICE, "ShmemAlloc: out of memory");
return newSpace;
}
@ -336,7 +331,7 @@ ShmemInitHash(char *name, /* table string name for shmem index */
int hash_flags) /* info about infoP */
{
bool found;
long *location;
void *location;
/*
* Hash tables allocated in shared memory have a fixed directory; it
@ -478,12 +473,12 @@ ShmemPIDDestroy(int pid)
* the object is already in the shmem index (hence, already
* initialized).
*/
long *
ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
void *
ShmemInitStruct(char *name, Size size, bool *foundPtr)
{
ShmemIndexEnt *result,
item;
long *structPtr;
void *structPtr;
strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
item.location = BAD_LOCATION;
@ -498,27 +493,27 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
#endif
/*
* If the shmem index doesnt exist, we fake it.
* If the shmem index doesn't exist, we fake it.
*
* If we are creating the first shmem index, then let shmemalloc()
* allocate the space for a new HTAB. Otherwise, find the old one
* and return that. Notice that the ShmemIndexLock is held until
* the shmem index has been completely initialized.
*/
Assert(!strcmp(name, strname));
Assert(strcmp(name, strname) == 0);
if (ShmemBootstrap)
{
/* in POSTMASTER/Single process */
*foundPtr = FALSE;
return (long *) ShmemAlloc(size);
return ShmemAlloc(size);
}
else
{
Assert(ShmemIndexOffset);
*foundPtr = TRUE;
return (long *) MAKE_PTR(*ShmemIndexOffset);
return (void *) MAKE_PTR(*ShmemIndexOffset);
}
@ -554,12 +549,12 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
/* let caller print its message too */
return NULL;
}
structPtr = (long *) MAKE_PTR(result->location);
structPtr = (void *) MAKE_PTR(result->location);
}
else
{
/* It isn't in the table yet. allocate and initialize it */
structPtr = ShmemAlloc((long) size);
structPtr = ShmemAlloc(size);
if (!structPtr)
{
/* out of memory */

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.71 2000/06/17 23:41:39 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.72 2000/06/28 03:32:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1090,7 +1090,7 @@ inv_newtuple(LargeObjectDesc *obj_desc,
ntup->t_len = tupsize;
ItemPointerSet(&ntup->t_self, BufferGetBlockNumber(buffer), off);
LastOidProcessed = ntup->t_data->t_oid = newoid();
ntup->t_data->t_oid = newoid();
TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_data->t_xmin));
ntup->t_data->t_cmin = GetCurrentCommandId();
StoreInvalidTransactionId(&(ntup->t_data->t_xmax));

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.69 2000/06/04 01:44:32 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.70 2000/06/28 03:32:07 tgl Exp $
*
* NOTES
* Outside modules can create a lock table and acquire/release
@ -225,6 +225,11 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable,
* has its name stored in the shmem index at its creation. It
* is wasteful, in this case, but not much space is involved.
*
* NOTE: data structures allocated here are allocated permanently, using
* TopMemoryContext and shared memory. We don't ever release them anyway,
* and in normal multi-backend operation the lock table structures set up
* by the postmaster are inherited by each backend, so they must be in
* TopMemoryContext.
*/
LOCKMETHOD
LockMethodTableInit(char *tabName,
@ -246,22 +251,13 @@ LockMethodTableInit(char *tabName,
return INVALID_LOCKMETHOD;
}
/* allocate a string for the shmem index table lookup */
shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32));
if (!shmemName)
{
elog(NOTICE, "LockMethodTableInit: couldn't malloc string %s \n", tabName);
return INVALID_LOCKMETHOD;
}
/* Allocate a string for the shmem index table lookups. */
/* This is just temp space in this routine, so palloc is OK. */
shmemName = (char *) palloc(strlen(tabName) + 32);
/* each lock table has a non-shared header */
lockMethodTable = (LOCKMETHODTABLE *) palloc((unsigned) sizeof(LOCKMETHODTABLE));
if (!lockMethodTable)
{
elog(NOTICE, "LockMethodTableInit: couldn't malloc lock table %s\n", tabName);
pfree(shmemName);
return INVALID_LOCKMETHOD;
}
/* each lock table has a non-shared, permanent header */
lockMethodTable = (LOCKMETHODTABLE *)
MemoryContextAlloc(TopMemoryContext, sizeof(LOCKMETHODTABLE));
/* ------------------------
* find/acquire the spinlock for the table
@ -269,7 +265,6 @@ LockMethodTableInit(char *tabName,
*/
SpinAcquire(LockMgrLock);
/* -----------------------
* allocate a control structure from shared memory or attach to it
* if it already exists.
@ -277,7 +272,7 @@ LockMethodTableInit(char *tabName,
*/
sprintf(shmemName, "%s (ctl)", tabName);
lockMethodTable->ctl = (LOCKMETHODCTL *)
ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found);
ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
if (!lockMethodTable->ctl)
{
@ -910,7 +905,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode);
old_status = pstrdup(get_ps_display());
new_status = palloc(strlen(get_ps_display()) + 10);
new_status = (char *) palloc(strlen(get_ps_display()) + 10);
strcpy(new_status, get_ps_display());
strcat(new_status, " waiting");
set_ps_display(new_status);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -47,7 +47,7 @@
* This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95
*
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
*/
#include <sys/time.h>
#include <unistd.h>
@ -119,7 +119,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
/* attach to the free list */
ProcGlobal = (PROC_HDR *)
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
/* --------------------
* We're the first - initialize.
@ -185,7 +185,7 @@ InitProcess(IPCKey key)
/* attach to the free list */
ProcGlobal = (PROC_HDR *)
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
if (!found)
{
/* this should not happen. InitProcGlobal() is called before this. */
@ -218,7 +218,7 @@ InitProcess(IPCKey key)
* cleanup dead processes).
*/
MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
if (!MyProc)
{
SpinRelease(ProcStructLock);
@ -458,7 +458,7 @@ ProcQueueAlloc(char *name)
{
bool found;
PROC_QUEUE *queue = (PROC_QUEUE *)
ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
if (!queue)
return NULL;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.71 2000/06/19 23:37:08 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.72 2000/06/28 03:32:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -94,19 +94,15 @@ static BlockNumber _mdnblocks(File file, Size blcksz);
int
mdinit()
{
MemoryContext oldcxt;
int i;
MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
if (MdCxt == (MemoryContext) NULL)
return SM_FAIL;
MdCxt = AllocSetContextCreate(TopMemoryContext,
"MdSmgr",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(MdCxt);
Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
MemoryContextSwitchTo(oldcxt);
if (Md_fdvec == (MdfdVec *) NULL)
return SM_FAIL;
Md_fdvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
@ -208,7 +204,6 @@ mdunlink(Relation reln)
int nblocks;
int fd;
MdfdVec *v;
MemoryContext oldcxt;
/*
* If the relation is already unlinked,we have nothing to do any more.
@ -238,7 +233,6 @@ mdunlink(Relation reln)
Md_fdvec[fd].mdfd_flags = (uint16) 0;
oldcxt = MemoryContextSwitchTo(MdCxt);
#ifndef LET_OS_MANAGE_FILESIZE
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
{
@ -256,7 +250,6 @@ mdunlink(Relation reln)
FileTruncate(v->mdfd_vfd, 0);
FileUnlink(v->mdfd_vfd);
#endif
MemoryContextSwitchTo(oldcxt);
_fdvec_free(fd);
@ -400,9 +393,7 @@ static void
mdclose_fd(int fd)
{
MdfdVec *v;
MemoryContext oldcxt;
oldcxt = MemoryContextSwitchTo(MdCxt);
#ifndef LET_OS_MANAGE_FILESIZE
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
{
@ -446,7 +437,6 @@ mdclose_fd(int fd)
}
}
#endif
MemoryContextSwitchTo(oldcxt);
_fdvec_free(fd);
}
@ -751,11 +741,8 @@ mdtruncate(Relation reln, int nblocks)
int curnblk;
int fd;
MdfdVec *v;
#ifndef LET_OS_MANAGE_FILESIZE
MemoryContext oldcxt;
int priorblocks;
#endif
/*
@ -772,7 +759,6 @@ mdtruncate(Relation reln, int nblocks)
v = &Md_fdvec[fd];
#ifndef LET_OS_MANAGE_FILESIZE
oldcxt = MemoryContextSwitchTo(MdCxt);
priorblocks = 0;
while (v != (MdfdVec *) NULL)
{
@ -825,7 +811,6 @@ mdtruncate(Relation reln, int nblocks)
}
priorblocks += RELSEG_SIZE;
}
MemoryContextSwitchTo(oldcxt);
#else
if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
return -1;
@ -833,8 +818,7 @@ mdtruncate(Relation reln, int nblocks)
#endif
return nblocks;
} /* mdtruncate */
}
/*
* mdcommit() -- Commit a transaction.
@ -907,7 +891,6 @@ _fdvec_alloc()
MdfdVec *nvec;
int fdvec,
i;
MemoryContext oldcxt;
if (Md_Free >= 0) /* get from free list */
{
@ -930,15 +913,11 @@ _fdvec_alloc()
Nfds *= 2;
oldcxt = MemoryContextSwitchTo(MdCxt);
nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
nvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
MemSet(nvec, 0, Nfds * sizeof(MdfdVec));
memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
memcpy(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
pfree(Md_fdvec);
MemoryContextSwitchTo(oldcxt);
Md_fdvec = nvec;
/* Set new free list */
@ -976,7 +955,6 @@ _fdvec_free(int fdvec)
static MdfdVec *
_mdfd_openseg(Relation reln, int segno, int oflags)
{
MemoryContext oldcxt;
MdfdVec *v;
int fd;
char *path,
@ -1003,9 +981,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags)
return (MdfdVec *) NULL;
/* allocate an mdfdvec entry for it */
oldcxt = MemoryContextSwitchTo(MdCxt);
v = (MdfdVec *) palloc(sizeof(MdfdVec));
MemoryContextSwitchTo(oldcxt);
v = (MdfdVec *) MemoryContextAlloc(MdCxt, sizeof(MdfdVec));
/* fill the entry */
v->mdfd_vfd = fd;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.161 2000/06/22 22:31:20 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.162 2000/06/28 03:32:18 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -79,7 +79,6 @@ bool Log_connections = false;
CommandDest whereToSendOutput = Debug;
extern void BaseInit(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(void);
@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS);
extern char XLogDir[];
extern char ControlFilePath[];
extern int lockingOff;
extern int NBuffers;
static bool dontExecute = false;
int dontExecute = 0;
static bool IsEmptyQuery = false;
/* note: these declarations had better match tcopprot.h */
@ -101,8 +98,6 @@ bool Warn_restart_ready = false;
bool InError = false;
bool ExitAfterAbort = false;
extern int NBuffers;
static bool EchoQuery = false; /* default don't echo */
char pg_pathname[MAXPGPATH];
FILE *StatFp = NULL;
@ -133,7 +128,6 @@ int XfuncMode = 0;
static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf);
static void pg_exec_query(char *query_string);
static void SigHupHandler(SIGNAL_ARGS);
static void FloatExceptionHandler(SIGNAL_ARGS);
static void quickdie(SIGNAL_ARGS);
@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf)
static int
ReadCommand(StringInfo inBuf)
{
MemoryContext oldcontext;
int result;
/*
* Make sure any expansion of inBuf happens in permanent memory
* context, so that we can keep using it for future command cycles.
*/
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
if (IsUnderPostmaster)
result = SocketBackend(inBuf);
else
result = InteractiveBackend(inBuf);
MemoryContextSwitchTo(oldcontext);
return result;
}
@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf)
* multiple queries and/or the rewriter might expand one query to several.
*/
List *
pg_parse_and_rewrite(char *query_string, /* string to execute */
Oid *typev,/* argument types */
int nargs, /* number of arguments */
bool aclOverride)
pg_parse_and_rewrite(char *query_string, /* string to execute */
Oid *typev, /* parameter types */
int nargs) /* number of parameters */
{
List *querytree_list;
List *querytree_list_item;
@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
querytree_list = new_list;
/* ----------------
* (3) If ACL override is requested, mark queries for no ACL check.
* ----------------
*/
if (aclOverride)
{
foreach(querytree_list_item, querytree_list)
{
List *l;
querytree = (Query *) lfirst(querytree_list_item);
if (querytree->commandType == CMD_UTILITY)
continue;
foreach(l, querytree->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
rte->skipAcl = TRUE;
}
}
}
if (Debug_print_rewritten)
{
if (Debug_pretty_print)
@ -516,63 +478,66 @@ pg_plan_query(Query *querytree)
/* ----------------------------------------------------------------
* pg_exec_query()
* pg_exec_query_dest()
*
* Takes a querystring, runs the parser/utilities or
* parser/planner/executor over it as necessary
* Begin Transaction Should have been called before this
* and CommitTransaction After this is called
* This is strictly because we do not allow for nested xactions.
* parser/planner/executor over it as necessary.
*
* NON-OBVIOUS-RESTRICTIONS
* this function _MUST_ allocate a new "parsetree" each time,
* since it may be stored in a named portal and should not
* change its value.
* Assumptions:
*
* Caller is responsible for calling StartTransactionCommand() beforehand
* and CommitTransactionCommand() afterwards (if successful).
*
* The CurrentMemoryContext at entry references a context that is
* appropriate for execution of individual queries (typically this will be
* TransactionCommandContext). Note that this routine resets that context
* after each individual query, so don't store anything there that
* must outlive the call!
*
* parse_context references a context suitable for holding the
* parse/rewrite trees (typically this will be QueryContext).
* This context must be longer-lived than the CurrentMemoryContext!
* In fact, if the query string might contain BEGIN/COMMIT commands,
* parse_context had better outlive TopTransactionContext!
*
* We could have hard-wired knowledge about QueryContext and
* TransactionCommandContext into this routine, but it seems better
* not to, in case callers from outside this module need to use some
* other contexts.
*
* ----------------------------------------------------------------
*/
static void
pg_exec_query(char *query_string)
{
pg_exec_query_dest(query_string, whereToSendOutput, FALSE);
}
#ifdef NOT_USED
void
pg_exec_query_acl_override(char *query_string)
{
pg_exec_query_dest(query_string, whereToSendOutput, TRUE);
}
#endif
void
pg_exec_query_dest(char *query_string, /* string to execute */
CommandDest dest, /* where results should go */
bool aclOverride) /* to give utility commands power
* of superusers */
MemoryContext parse_context) /* context for parsetrees */
{
List *querytree_list;
/* parse and rewrite the queries */
querytree_list = pg_parse_and_rewrite(query_string, NULL, 0,
aclOverride);
MemoryContext oldcontext;
List *querytree_list,
*querytree_item;
/*
* NOTE: we do not use "foreach" here because we want to be sure the
* list pointer has been advanced before the query is executed. We
* need to do that because VACUUM has a nasty little habit of doing
* CommitTransactionCommand at startup, and that will release the
* memory holding our parse list :-(. This needs a better solution
* --- currently, the code will crash if someone submits "vacuum;
* something-else" in a single query string. But memory allocation
* needs redesigned anyway, so this will have to do for now.
* Switch to appropriate context for constructing parsetrees.
*/
while (querytree_list)
{
Query *querytree = (Query *) lfirst(querytree_list);
oldcontext = MemoryContextSwitchTo(parse_context);
querytree_list = lnext(querytree_list);
/*
* Parse and rewrite the query or queries.
*/
querytree_list = pg_parse_and_rewrite(query_string, NULL, 0);
/*
* Switch back to execution context for planning and execution.
*/
MemoryContextSwitchTo(oldcontext);
/*
* Run through the query or queries and execute each one.
*/
foreach(querytree_item, querytree_list)
{
Query *querytree = (Query *) lfirst(querytree_item);
/* if we got a cancel signal in parsing or prior command, quit */
if (QueryCancel)
@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string, /* string to execute */
if (Show_executor_stats)
ResetUsage();
if (DebugLvl > 1)
elog(DEBUG, "ProcessQuery");
ProcessQuery(querytree, plan, dest);
if (dontExecute)
{
/* don't execute it, just show the query plan */
print_plan(plan, querytree);
}
else
{
if (DebugLvl > 1)
elog(DEBUG, "ProcessQuery");
ProcessQuery(querytree, plan, dest);
}
if (Show_executor_stats)
{
@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string, /* string to execute */
* between queries so that the effects of early queries are
* visible to subsequent ones.
*/
CommandCounterIncrement();
/*
* Also, clear the execution context to recover temporary
* memory used by the query. NOTE: if query string contains
* BEGIN/COMMIT transaction commands, execution context may
* now be different from what we were originally passed;
* so be careful to clear current context not "oldcontext".
*/
MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
}
}
@ -821,6 +801,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
extern char *optarg;
extern int DebugLvl;
/*
* Fire up essential subsystems: error and memory management
*
* If we are running under the postmaster, this is done already.
*/
if (!IsUnderPostmaster)
{
EnableExceptionHandling(true);
MemoryContextInit();
}
/*
* Set default values for command-line options.
*/
@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
break;
case 'i':
dontExecute = 1;
dontExecute = true;
break;
case 'L':
@ -1182,11 +1173,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
*
* Note that postmaster already blocked ALL signals to make us happy.
*/
if (!IsUnderPostmaster)
{
PG_INITMASK();
PG_SETMASK(&BlockSig);
}
pqinitmask();
#ifdef HAVE_SIGPROCMASK
sigdelset(&BlockSig, SIGUSR1);
@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
BlockSig &= ~(sigmask(SIGUSR1));
#endif
PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
pqsignal(SIGQUIT, handle_warn); /* handle error */
@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
pqsignal(SIGTTOU, SIG_DFL);
pqsignal(SIGCONT, SIG_DFL);
PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
/*
* Get user name (needed now in case it is the default database name)
* and check command line validity
@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
on_shmem_exit(remove_all_temp_relations, NULL);
{
MemoryContext oldcontext = MemoryContextSwitchTo(TopMemoryContext);
parser_input = makeStringInfo(); /* initialize input buffer */
MemoryContextSwitchTo(oldcontext);
}
/*
* Send this backend's cancellation info to the frontend.
*/
@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.161 $ $Date: 2000/06/22 22:31:20 $\n");
puts("$Revision: 1.162 $ $Date: 2000/06/28 03:32:18 $\n");
}
/*
@ -1397,6 +1377,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
SetProcessingMode(NormalProcessing);
/*
* Create the memory context we will use in the main loop.
*
* QueryContext is reset once per iteration of the main loop,
* ie, upon completion of processing of each supplied query string.
* It can therefore be used for any data that should live just as
* long as the query string --- parse trees, for example.
*/
QueryContext = AllocSetContextCreate(TopMemoryContext,
"QueryContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/*
* POSTGRES main processing loop begins here
*
@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (sigsetjmp(Warn_restart, 1) != 0)
{
/* Make sure we are in a valid memory context */
MemoryContextSwitchTo(TopMemoryContext);
/*
* Make sure we are in a valid memory context during recovery.
*
* We use ErrorContext in hopes that it will have some free space
* even if we're otherwise up against it...
*/
MemoryContextSwitchTo(ErrorContext);
if (DebugLvl >= 1)
elog(DEBUG, "AbortCurrentTransaction");
AbortCurrentTransaction();
InError = false;
if (ExitAfterAbort)
{
ProcReleaseLocks(); /* Just to be sure... */
proc_exit(0);
}
/*
* If we recovered successfully, return to normal top-level context
* and clear ErrorContext for next time.
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextResetAndDeleteChildren(ErrorContext);
InError = false;
}
Warn_restart_ready = true; /* we can now handle elog(ERROR) */
@ -1430,7 +1436,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
for (;;)
{
set_ps_display("idle");
/*
* Release storage left over from prior query cycle, and
* create a new query input buffer in the cleared QueryContext.
*/
MemoryContextSwitchTo(QueryContext);
MemoryContextResetAndDeleteChildren(QueryContext);
parser_input = makeStringInfo();
/* XXX this could be moved after ReadCommand below to get more
* sensical behaviour */
@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
* (3) read a command (loop blocks here)
* ----------------
*/
set_ps_display("idle");
firstchar = ReadCommand(parser_input);
QueryCancel = false; /* forget any earlier CANCEL signal */
@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
elog(DEBUG, "StartTransactionCommand");
StartTransactionCommand();
pg_exec_query(parser_input->data);
pg_exec_query_dest(parser_input->data,
whereToSendOutput,
QueryContext);
/*
* Invoke IMMEDIATE constraint triggers
@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
* (6) commit the current transaction
*
* Note: if we had an empty input buffer, then we didn't
* call pg_exec_query, so we don't bother to commit this transaction.
* call pg_exec_query_dest, so we don't bother to commit
* this transaction.
* ----------------
*/
if (!IsEmptyQuery)
@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
#ifdef SHOW_MEMORY_STATS
/* print global-context stats at each commit for leak tracking */
if (ShowStats)
GlobalMemoryStats();
MemoryContextStats(TopMemoryContext);
#endif
}
else

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.34 2000/06/12 03:40:40 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.35 2000/06/28 03:32:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,8 +22,6 @@
#include "utils/ps_status.h"
static char *CreateOperationTag(int operationType);
static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
Node *limcount);
/* ----------------------------------------------------------------
@ -115,7 +113,7 @@ CreateOperationTag(int operationType)
default:
elog(DEBUG, "CreateOperationTag: unknown operation type %d",
operationType);
tag = NULL;
tag = "???";
break;
}
@ -123,31 +121,18 @@ CreateOperationTag(int operationType)
}
/* ----------------
* ProcessPortal
* PreparePortal
* ----------------
*/
void
ProcessPortal(char *portalName,
Query *parseTree,
Plan *plan,
EState *state,
TupleDesc attinfo,
CommandDest dest)
Portal
PreparePortal(char *portalName)
{
Portal portal;
MemoryContext portalContext;
/* ----------------
* Check for reserved or already-in-use portal name.
* Check for already-in-use portal name.
* ----------------
*/
if (PortalNameIsSpecial(portalName))
elog(ERROR,
"The portal name \"%s\" is reserved for internal use",
portalName);
portal = GetPortalByName(portalName);
if (PortalIsValid(portal))
{
@ -158,70 +143,39 @@ ProcessPortal(char *portalName,
}
/* ----------------
* Convert the current blank portal into the user-specified
* portal and initialize the state and query descriptor.
*
* Since the parsetree has been created in the current blank portal,
* we don't have to do any work to copy it into the user-named portal.
* Create the new portal and make its memory context active.
* ----------------
*/
portal = CreatePortal(portalName);
portal = BlankPortalAssignName(portalName);
MemoryContextSwitchTo(PortalGetHeapMemory(portal));
PortalSetQuery(portal,
CreateQueryDesc(parseTree, plan, dest),
attinfo,
state,
PortalCleanup);
/* ----------------
* Now create a new blank portal and switch to it.
* Otherwise, the new named portal will be cleaned at statement end.
*
* Note: portals will only be supported within a BEGIN...END
* block in the near future. Later, someone will fix it to
* do what is possible across transaction boundries. -hirohama
* ----------------
*/
portalContext = (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL));
MemoryContextSwitchTo(portalContext);
StartPortalAllocMode(DefaultAllocMode, 0);
return portal;
}
/* ----------------------------------------------------------------
* ProcessQueryDesc
* ProcessQuery
*
* Read the comments for ProcessQuery() below...
* Execute a plan, the non-parallel version
* ----------------------------------------------------------------
*/
static void
ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
void
ProcessQuery(Query *parsetree,
Plan *plan,
CommandDest dest)
{
Query *parseTree;
Plan *plan;
int operation;
char *tag = NULL;
int operation = parsetree->commandType;
char *tag;
bool isRetrieveIntoPortal;
bool isRetrieveIntoRelation;
Portal portal = NULL;
char *intoName = NULL;
QueryDesc *queryDesc;
EState *state;
TupleDesc attinfo;
bool isRetrieveIntoPortal;
bool isRetrieveIntoRelation;
char *intoName = NULL;
CommandDest dest;
/* ----------------
* get info from the query desc
* ----------------
*/
parseTree = queryDesc->parsetree;
plan = queryDesc->plantree;
operation = queryDesc->operation;
set_ps_display(tag = CreateOperationTag(operation));
dest = queryDesc->dest;
/* ----------------
* initialize portal/into relation status
@ -232,11 +186,11 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
if (operation == CMD_SELECT)
{
if (parseTree->isPortal)
if (parsetree->isPortal)
{
isRetrieveIntoPortal = true;
intoName = parseTree->into;
if (parseTree->isBinary)
intoName = parsetree->into;
if (parsetree->isBinary)
{
/*
@ -244,19 +198,38 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
* (externalized form) to RemoteInternal (internalized
* form)
*/
dest = queryDesc->dest = RemoteInternal;
dest = RemoteInternal;
}
}
else if (parseTree->into != NULL)
else if (parsetree->into != NULL)
{
/* select into table */
isRetrieveIntoRelation = true;
}
}
/* ----------------
* when performing a retrieve into, we override the normal
* 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);
}
/* ----------------
* Now we can create the QueryDesc object (this is also in
* the portal context, if portal retrieve).
* ----------------
*/
queryDesc = CreateQueryDesc(parsetree, plan, dest);
/* ----------------
* When performing a retrieve into, we override the normal
* communication destination during the processing of the
* the query. This only affects the tuple-output function
* - the correct destination will still see BeginCommand()
@ -293,26 +266,19 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
dest);
/* ----------------
* Named portals do not do a "fetch all" initially, so now
* we return since ExecMain has been called with EXEC_START
* to initialize the query plan.
*
* Note: ProcessPortal transforms the current "blank" portal
* into a named portal and creates a new blank portal so
* everything we allocated in the current "blank" memory
* context will be preserved across queries. -cim 2/22/91
* If retrieve into portal, stop now; we do not run the plan
* until a FETCH command is received.
* ----------------
*/
if (isRetrieveIntoPortal)
{
PortalExecutorHeapMemory = NULL;
PortalSetQuery(portal,
queryDesc,
attinfo,
state,
PortalCleanup);
ProcessPortal(intoName,
parseTree,
plan,
state,
attinfo,
dest);
MemoryContextSwitchTo(TransactionCommandContext);
EndCommand(tag, dest);
return;
@ -323,14 +289,14 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
* actually run the plan..
* ----------------
*/
ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
ExecutorRun(queryDesc, state, EXEC_RUN,
parsetree->limitOffset, parsetree->limitCount);
/* save infos for EndCommand */
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
/* ----------------
* now, we close down all the scans and free allocated resources...
* with ExecutorEnd()
* Now, we close down all the scans and free allocated resources.
* ----------------
*/
ExecutorEnd(queryDesc, state);
@ -341,31 +307,3 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
*/
EndCommand(tag, dest);
}
/* ----------------------------------------------------------------
* ProcessQuery
*
* Execute a plan, the non-parallel version
* ----------------------------------------------------------------
*/
void
ProcessQuery(Query *parsetree,
Plan *plan,
CommandDest dest)
{
QueryDesc *queryDesc;
extern int dontExecute; /* from postgres.c */
extern void print_plan(Plan *p, Query *parsetree); /* from print.c */
queryDesc = CreateQueryDesc(parsetree, plan, dest);
if (dontExecute)
{
/* don't execute it, just show the query plan */
print_plan(plan, parsetree);
}
else
ProcessQueryDesc(queryDesc, parsetree->limitOffset,
parsetree->limitCount);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.67 2000/06/19 03:54:31 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.68 2000/06/28 03:32:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -60,10 +60,6 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
static CatCache *Caches = NULL; /* head of list of caches */
GlobalMemory CacheCxt; /* context in which caches are allocated */
/* CacheCxt is global because relcache uses it too. */
/* ----------------
* EQPROC is used in CatalogCacheInitializeCache to find the equality
@ -135,6 +131,28 @@ cc_hashname(PG_FUNCTION_ARGS)
}
/*
* Standard routine for creating cache context if it doesn't exist yet
*
* There are a lot of places (probably far more than necessary) that check
* whether CacheMemoryContext exists yet and want to create it if not.
* We centralize knowledge of exactly how to create it here.
*/
void
CreateCacheMemoryContext(void)
{
/* Purely for paranoia, check that context doesn't exist;
* caller probably did so already.
*/
if (!CacheMemoryContext)
CacheMemoryContext = AllocSetContextCreate(TopMemoryContext,
"CacheMemoryContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
}
/* --------------------------------
* CatalogCacheInitializeCache
* --------------------------------
@ -183,9 +201,10 @@ CatalogCacheInitializeCache(CatCache * cache,
* do not vanish at the end of a transaction
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* If no relation was passed we must open it to get access to
@ -415,7 +434,7 @@ CatalogCacheComputeTupleHashIndex(CatCache * cacheInOutP,
/* --------------------------------
* CatCacheRemoveCTup
*
* NB: assumes caller has switched to CacheCxt
* NB: assumes caller has switched to CacheMemoryContext
* --------------------------------
*/
static void
@ -477,9 +496,10 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */
* switch to the cache context for our memory allocations
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* inspect every cache that could contain the tuple
@ -552,10 +572,10 @@ ResetSystemCache()
* do not vanish at the end of a transaction
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* here we purge the contents of all the caches
@ -681,10 +701,10 @@ InitSysCache(char *relname,
* do not vanish at the end of a transaction
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* allocate a new cache structure
@ -839,14 +859,14 @@ SearchSelfReferences(CatCache * cache)
HeapScanDesc sd;
MemoryContext oldcxt;
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
rel = heap_open(cache->relationId, AccessShareLock);
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
ntp = heap_getnext(sd, 0);
if (!HeapTupleIsValid(ntp))
elog(ERROR, "SearchSelfReferences: tuple not found");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
indexSelfTuple = heap_copytuple(ntp);
MemoryContextSwitchTo(oldcxt);
heap_endscan(sd);
@ -868,14 +888,14 @@ SearchSelfReferences(CatCache * cache)
HeapScanDesc sd;
MemoryContext oldcxt;
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
rel = heap_open(cache->relationId, AccessShareLock);
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
ntp = heap_getnext(sd, 0);
if (!HeapTupleIsValid(ntp))
elog(ERROR, "SearchSelfReferences: tuple not found");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
MemoryContextSwitchTo(oldcxt);
heap_endscan(sd);
@ -908,7 +928,6 @@ SearchSysCache(CatCache * cache,
CatCTup *nct2;
Dlelem *elt;
HeapTuple ntp = NULL;
Relation relation;
MemoryContext oldcxt;
@ -1020,10 +1039,10 @@ SearchSysCache(CatCache * cache,
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* Scan the relation to find the tuple. If there's an index, and
@ -1060,12 +1079,13 @@ SearchSysCache(CatCache * cache,
*/
if (HeapTupleIsValid(indextp))
{
MemoryContextSwitchTo((MemoryContext) CacheCxt);
MemoryContextSwitchTo(CacheMemoryContext);
ntp = heap_copytuple(indextp);
/* this switch is probably not needed anymore: */
MemoryContextSwitchTo(oldcxt);
heap_freetuple(indextp);
}
MemoryContextSwitchTo((MemoryContext) CacheCxt);
MemoryContextSwitchTo(CacheMemoryContext);
}
else
{
@ -1084,7 +1104,7 @@ SearchSysCache(CatCache * cache,
ntp = heap_getnext(sd, 0);
MemoryContextSwitchTo((MemoryContext) CacheCxt);
MemoryContextSwitchTo(CacheMemoryContext);
if (HeapTupleIsValid(ntp))
{
@ -1097,7 +1117,7 @@ SearchSysCache(CatCache * cache,
heap_endscan(sd);
MemoryContextSwitchTo((MemoryContext) CacheCxt);
MemoryContextSwitchTo(CacheMemoryContext);
}
cache->busy = false;
@ -1205,9 +1225,10 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
* switch to the cache memory context
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* for each cache

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.103 2000/06/19 23:40:48 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.104 2000/06/28 03:32:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -917,10 +917,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
/* ----------------
* allocate storage for the relation descriptor,
* initialize relation->rd_rel and get the access method id.
* The storage is allocated in memory context CacheCxt.
* The storage is allocated in memory context CacheMemoryContext.
* ----------------
*/
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
relation = AllocateRelationDesc(oldrelation, natts, relp);
relam = relation->rd_rel->relam;
@ -1383,7 +1383,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
if (relation->rd_isnailed)
return;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/*
* Remove relation from hash tables
@ -1574,7 +1574,7 @@ RelationForgetRelation(Oid rid)
List *curr;
List *prev = NIL;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
foreach(curr, newlyCreatedRelns)
{
@ -1731,10 +1731,7 @@ RelationRegisterRelation(Relation relation)
{
MemoryContext oldcxt;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
if (oldcxt != (MemoryContext) CacheCxt)
elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
RelationInitLockInfo(relation);
@ -1769,7 +1766,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
if (newlyCreatedRelns == NULL)
return;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
while (newlyCreatedRelns)
{
@ -1822,10 +1819,10 @@ RelationInitialize(void)
* switch to cache memory context
* ----------------
*/
if (!CacheCxt)
CacheCxt = CreateGlobalMemory("Cache");
if (!CacheMemoryContext)
CreateCacheMemoryContext();
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* create global caches
@ -2186,7 +2183,7 @@ RelationGetIndexList(Relation relation)
heap_close(indrel, AccessShareLock);
/* Now save a copy of the completed list in the relcache entry. */
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
relation->rd_indexlist = listCopy(result);
relation->rd_indexfound = true;
MemoryContextSwitchTo(oldcxt);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.24 2000/06/20 06:41:12 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.25 2000/06/28 03:32:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -67,7 +67,7 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
MemoryContext oldcxt;
TempTable *temp_rel;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
temp_rel = (TempTable *) palloc(sizeof(TempTable));
temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
@ -135,7 +135,7 @@ remove_temp_relation(Oid relid)
List *l,
*prev;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
prev = NIL;
l = temp_rels;
@ -185,7 +185,7 @@ invalidate_temp_relations(void)
List *l,
*prev;
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
prev = NIL;
l = temp_rels;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.60 2000/06/04 15:06:29 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.61 2000/06/28 03:32:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -27,7 +27,7 @@
#include <sys/time.h>
#include <ctype.h>
#ifdef ENABLE_SYSLOG
# include <syslog.h>
#include <syslog.h>
#endif
#include "libpq/libpq.h"
@ -89,10 +89,9 @@ static int ElogDebugIndentLevel = 0;
*--------------------
*/
void
elog(int lev, const char *fmt,...)
elog(int lev, const char *fmt, ...)
{
va_list ap;
/*
* The expanded format and final output message are dynamically
* allocated if necessary, but not if they fit in the "reasonable
@ -101,12 +100,21 @@ elog(int lev, const char *fmt,...)
* working (since memory-clobber errors often take out malloc first).
* Don't make these buffers unreasonably large though, on pain of
* having to chase a bug with no error message.
*
* Note that we use malloc() not palloc() because we want to retain
* control if we run out of memory. palloc() would recursively call
* elog(ERROR), which would be all right except if we are working on a
* FATAL or REALLYFATAL error. We'd lose track of the fatal condition
* and report a mere ERROR to outer loop, which would be a Bad Thing.
* So, we substitute an appropriate message in-place, without downgrading
* the level if it's above ERROR.
*/
char fmt_fixedbuf[128];
char msg_fixedbuf[256];
char *fmt_buf = fmt_fixedbuf;
char *msg_buf = msg_fixedbuf;
/* this buffer is only used for strange values of lev: */
char prefix_buf[32];
/* this buffer is only used if errno has a bogus value: */
char errorstr_buf[32];
const char *errorstr;
@ -115,7 +123,6 @@ elog(int lev, const char *fmt,...)
char *bp;
int indent = 0;
int space_needed;
int len;
/* size of the prefix needed for timestamp and pid, if enabled */
size_t timestamp_size;
@ -123,6 +130,15 @@ elog(int lev, const char *fmt,...)
if (lev <= DEBUG && Debugfile < 0)
return; /* ignore debug msgs if noplace to send */
/* save errno string for %m */
if (errno < sys_nerr && errno >= 0)
errorstr = strerror(errno);
else
{
sprintf(errorstr_buf, "error %d", errno);
errorstr = errorstr_buf;
}
if (lev == ERROR || lev == FATAL)
{
/* this is probably redundant... */
@ -156,21 +172,11 @@ elog(int lev, const char *fmt,...)
prefix = "ERROR: ";
break;
default:
/* temporarily use msg buf for prefix */
sprintf(msg_fixedbuf, "FATAL %d: ", lev);
prefix = msg_fixedbuf;
sprintf(prefix_buf, "FATAL %d: ", lev);
prefix = prefix_buf;
break;
}
/* get errno string for %m */
if (errno < sys_nerr && errno >= 0)
errorstr = strerror(errno);
else
{
sprintf(errorstr_buf, "error %d", errno);
errorstr = errorstr_buf;
}
timestamp_size = 0;
if (Log_timestamp)
timestamp_size += TIMESTAMP_SIZE;
@ -190,9 +196,13 @@ elog(int lev, const char *fmt,...)
fmt_buf = (char *) malloc(space_needed);
if (fmt_buf == NULL)
{
/* We're up against it, convert to fatal out-of-memory error */
/* We're up against it, convert to out-of-memory error */
fmt_buf = fmt_fixedbuf;
lev = REALLYFATAL;
if (lev < FATAL)
{
lev = ERROR;
prefix = "ERROR: ";
}
fmt = "elog: out of memory"; /* this must fit in
* fmt_fixedbuf! */
}
@ -281,15 +291,20 @@ elog(int lev, const char *fmt,...)
msg_buf = (char *) malloc(space_needed);
if (msg_buf == NULL)
{
/* We're up against it, convert to fatal out-of-memory error */
/* We're up against it, convert to out-of-memory error */
msg_buf = msg_fixedbuf;
lev = REALLYFATAL;
if (lev < FATAL)
{
lev = ERROR;
prefix = "ERROR: ";
}
msg_buf[0] = '\0';
if (Log_timestamp)
strcat(msg_buf, print_timestamp());
if (Log_pid)
strcat(msg_buf, print_pid());
strcat(msg_buf, "FATAL: elog: out of memory");
strcat(msg_buf, prefix);
strcat(msg_buf, "elog: out of memory");
break;
}
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.42 2000/06/15 04:10:29 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.43 2000/06/28 03:32:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -134,7 +134,7 @@ load_external_function(char *filename, char *funcname)
file_scanner = (DynamicFileList *)
malloc(sizeof(DynamicFileList) + strlen(filename));
if (file_scanner == NULL)
elog(FATAL, "Out of memory in load_external_function");
elog(ERROR, "Out of memory in load_external_function");
MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
strcpy(file_scanner->filename, filename);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.31 2000/04/12 17:16:00 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.32 2000/06/28 03:32:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -56,8 +56,7 @@
/*
* Private function prototypes
*/
static long *DynaHashAlloc(unsigned int size);
static void DynaHashFree(Pointer ptr);
static void *DynaHashAlloc(Size size);
static uint32 call_hash(HTAB *hashp, char *k);
static SEG_OFFSET seg_alloc(HTAB *hashp);
static int bucket_alloc(HTAB *hashp);
@ -66,9 +65,7 @@ static int expand_table(HTAB *hashp);
static int hdefault(HTAB *hashp);
static int init_htab(HTAB *hashp, int nelem);
typedef long *((*dhalloc_ptr) ());
#ifndef FRONTEND
/* ----------------
* memory allocation routines
*
@ -84,34 +81,24 @@ typedef long *((*dhalloc_ptr) ());
* do the latter -cim 1/19/91
* ----------------
*/
GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
static MemoryContext DynaHashCxt = NULL;
static long *
DynaHashAlloc(unsigned int size)
static void *
DynaHashAlloc(Size size)
{
if (!DynaHashCxt)
DynaHashCxt = CreateGlobalMemory("DynaHash");
DynaHashCxt = AllocSetContextCreate(TopMemoryContext,
"DynaHash",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
return (long *)
MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
}
static void
DynaHashFree(Pointer ptr)
{
MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
return MemoryContextAlloc(DynaHashCxt, size);
}
#define MEM_ALLOC DynaHashAlloc
#define MEM_FREE DynaHashFree
#else /* FRONTEND */
#define MEM_ALLOC palloc
#define MEM_FREE pfree
#endif /* FRONTEND */
/*
* pointer access macros. Shared memory implementation cannot
@ -147,7 +134,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
HTAB *hashp;
hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
hashp = (HTAB *) MEM_ALLOC(sizeof(HTAB));
MemSet(hashp, 0, sizeof(HTAB));
if (flags & HASH_FUNCTION)
@ -181,7 +168,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
/* setup hash table defaults */
hashp->hctl = NULL;
hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
hashp->alloc = MEM_ALLOC;
hashp->dir = NULL;
hashp->segbase = NULL;
@ -189,7 +176,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
if (!hashp->hctl)
{
hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
hashp->hctl = (HHDR *) hashp->alloc(sizeof(HHDR));
if (!hashp->hctl)
return 0;
}
@ -318,7 +305,8 @@ init_htab(HTAB *hashp, int nelem)
/* Allocate a directory */
if (!(hashp->dir))
{
hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
hashp->dir = (SEG_OFFSET *)
hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
if (!hashp->dir)
return -1;
}
@ -445,7 +433,7 @@ hash_destroy(HTAB *hashp)
/* cannot destroy a shared memory hash table */
Assert(!hashp->segbase);
/* allocation method must be one we know how to free, too */
Assert(hashp->alloc == (dhalloc_ptr) MEM_ALLOC);
Assert(hashp->alloc == MEM_ALLOC);
hash_stats("destroy", hashp);
@ -885,7 +873,7 @@ dir_realloc(HTAB *hashp)
new_dirsize = new_dsize * sizeof(SEG_OFFSET);
old_p = (char *) hashp->dir;
p = (char *) hashp->alloc((unsigned long) new_dirsize);
p = (char *) hashp->alloc((Size) new_dirsize);
if (p != NULL)
{
@ -906,8 +894,7 @@ seg_alloc(HTAB *hashp)
SEGMENT segp;
SEG_OFFSET segOffset;
segp = (SEGMENT) hashp->alloc((unsigned long)
sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
segp = (SEGMENT) hashp->alloc(sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
if (!segp)
return 0;
@ -937,8 +924,7 @@ bucket_alloc(HTAB *hashp)
/* make sure its aligned correctly */
bucketSize = MAXALIGN(bucketSize);
tmpBucket = (ELEMENT *)
hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
tmpBucket = (ELEMENT *) hashp->alloc(BUCKET_ALLOC_INCR * bucketSize);
if (!tmpBucket)
return 0;

View File

@ -4,14 +4,14 @@
# Makefile for utils/init
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.13 2000/05/29 05:45:32 tgl Exp $
# $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.14 2000/06/28 03:32:43 tgl Exp $
#
#-------------------------------------------------------------------------
SRCDIR = ../../..
include ../../../Makefile.global
OBJS = enbl.o findbe.o globals.o miscinit.o postinit.o
OBJS = findbe.o globals.o miscinit.o postinit.o
all: SUBSYS.o
@ -27,4 +27,3 @@ clean:
ifeq (depend,$(wildcard depend))
include depend
endif

View File

@ -1,47 +0,0 @@
/*-------------------------------------------------------------------------
*
* enbl.c
* POSTGRES module enable and disable support code.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/enbl.c,v 1.10 2000/01/26 05:57:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/module.h"
/*
* BypassEnable
* False iff enable/disable processing is required given on and "*countP."
*
* Note:
* As a side-effect, *countP is modified. It should be 0 initially.
*
* Exceptions:
* BadState if called with pointer to value 0 and false.
* BadArg if "countP" is invalid pointer.
* BadArg if on is invalid.
*/
bool
BypassEnable(int *enableCountInOutP, bool on)
{
AssertArg(PointerIsValid(enableCountInOutP));
AssertArg(BoolIsValid(on));
if (on)
{
*enableCountInOutP += 1;
return (bool) (*enableCountInOutP >= 2);
}
Assert(*enableCountInOutP >= 1);
*enableCountInOutP -= 1;
return (bool) (*enableCountInOutP >= 1);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.59 2000/05/30 00:49:56 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.60 2000/06/28 03:32:43 tgl Exp $
*
*
*-------------------------------------------------------------------------
@ -40,8 +40,6 @@
#include "mb/pg_wchar.h"
#endif
void BaseInit(void);
static void ReverifyMyDatabase(const char *name);
static void InitCommunication(void);
@ -222,8 +220,6 @@ InitCommunication()
* Be very careful with the order of calls in the InitPostgres function.
* --------------------------------
*/
extern int NBuffers;
int lockingOff = 0; /* backend -L switch */
/*
@ -405,21 +401,6 @@ InitPostgres(const char *dbname)
void
BaseInit(void)
{
/*
* Turn on the exception handler. Note: we cannot use elog, Assert,
* AssertState, etc. until after exception handling is on.
*/
EnableExceptionHandling(true);
/*
* Memory system initialization - we may call palloc after
* EnableMemoryContext()). Note that EnableMemoryContext() must
* happen before EnablePortalManager().
*/
EnableMemoryContext(true); /* initializes the "top context" */
EnablePortalManager(true); /* memory for portal/transaction stuff */
/*
* Attach to shared memory and semaphores, and initialize our
* input/output/debugging file descriptors.
@ -427,4 +408,6 @@ BaseInit(void)
InitCommunication();
DebugFileOpen();
smgrinit();
EnablePortalManager(); /* memory for portal/transaction stuff */
}

View File

@ -6,7 +6,7 @@
* WIN1250 client encoding support contributed by Pavel Behal
* SJIS UDC (NEC selection IBM kanji) support contributed by Eiji Tokuya
*
* $Id: conv.c,v 1.15 2000/05/20 13:12:26 ishii Exp $
* $Id: conv.c,v 1.16 2000/06/28 03:32:45 tgl Exp $
*
*
*/
@ -1521,7 +1521,8 @@ pg_encoding_conv_tbl pg_conv_tbl[] = {
};
#ifdef DEBUGMAIN
#include "utils/mcxt.h"
#include "postgres.h"
#include "utils/memutils.h"
/*
* testing for sjis2mic() and mic2sjis()
*/
@ -1565,21 +1566,23 @@ main()
void
elog(int lev, const char *fmt,...)
{
};
}
MemoryContext CurrentMemoryContext;
Pointer
void *
MemoryContextAlloc(MemoryContext context, Size size)
{
};
Pointer
MemoryContextRealloc(MemoryContext context,
Pointer pointer,
Size size)
{
};
}
void
MemoryContextFree(MemoryContext context, Pointer pointer)
pfree(void *pointer)
{
};
}
void *
repalloc(void *pointer, Size size)
{
}
#endif

View File

@ -4,14 +4,14 @@
# Makefile for utils/mmgr
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.8 2000/05/29 05:45:40 tgl Exp $
# $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.9 2000/06/28 03:32:50 tgl Exp $
#
#-------------------------------------------------------------------------
SRCDIR = ../../..
include ../../../Makefile.global
OBJS = aset.o mcxt.o palloc.o portalmem.o oset.o
OBJS = aset.o mcxt.o portalmem.o
all: SUBSYS.o

View File

@ -0,0 +1,379 @@
Proposal for memory allocation fixes, take 2 21-Jun-2000
--------------------------------------------
We know that Postgres has serious problems with memory leakage during
large queries that process a lot of pass-by-reference data. There is
no provision for recycling memory until end of query. This needs to be
fixed, even more so with the advent of TOAST which will allow very large
chunks of data to be passed around in the system. So, here is a proposal.
Background
----------
We already do most of our memory allocation in "memory contexts", which
are usually AllocSets as implemented by backend/utils/mmgr/aset.c. What
we need to do is create more contexts and define proper rules about when
they can be freed.
The basic operations on a memory context are:
* create a context
* allocate a chunk of memory within a context (equivalent of standard
C library's malloc())
* delete a context (including freeing all the memory allocated therein)
* reset a context (free all memory allocated in the context, but not the
context object itself)
Given a chunk of memory previously allocated from a context, one can
free it or reallocate it larger or smaller (corresponding to standard
library's free() and realloc() routines). These operations return memory
to or get more memory from the same context the chunk was originally
allocated in.
At all times there is a "current" context denoted by the
CurrentMemoryContext global variable. The backend macro palloc()
implicitly allocates space in that context. The MemoryContextSwitchTo()
operation selects a new current context (and returns the previous context,
so that the caller can restore the previous context before exiting).
The main advantage of memory contexts over plain use of malloc/free is
that the entire contents of a memory context can be freed easily, without
having to request freeing of each individual chunk within it. This is
both faster and more reliable than per-chunk bookkeeping. We already use
this fact to clean up at transaction end: by resetting all the active
contexts, we reclaim all memory. What we need are additional contexts
that can be reset or deleted at strategic times within a query, such as
after each tuple.
pfree/repalloc no longer depend on CurrentMemoryContext
-------------------------------------------------------
In this proposal, pfree() and repalloc() can be applied to any chunk
whether it belongs to CurrentMemoryContext or not --- the chunk's owning
context will be invoked to handle the operation, regardless. This is a
change from the old requirement that CurrentMemoryContext must be set
to the same context the memory was allocated from before one can use
pfree() or repalloc(). The old coding requirement is obviously fairly
error-prone, and will become more so the more context-switching we do;
so I think it's essential to use CurrentMemoryContext only for palloc.
We can avoid needing it for pfree/repalloc by putting restrictions on
context managers as discussed below.
We could even consider getting rid of CurrentMemoryContext entirely,
instead requiring the target memory context for allocation to be specified
explicitly. But I think that would be too much notational overhead ---
we'd have to pass an apppropriate memory context to called routines in
many places. For example, the copyObject routines would need to be passed
a context, as would function execution routines that return a
pass-by-reference datatype. And what of routines that temporarily
allocate space internally, but don't return it to their caller? We
certainly don't want to clutter every call in the system with "here is
a context to use for any temporary memory allocation you might want to
do". So there'd still need to be a global variable specifying a suitable
temporary-allocation context. That might as well be CurrentMemoryContext.
Additions to the memory-context mechanism
-----------------------------------------
If we are going to have more contexts, we need more mechanism for keeping
track of them; else we risk leaking whole contexts under error conditions.
We can do this by creating trees of "parent" and "child" contexts. When
creating a memory context, the new context can be specified to be a child
of some existing context. A context can have many children, but only one
parent. In this way the contexts form a forest (not necessarily a single
tree, since there could be more than one top-level context).
We then say that resetting or deleting any particular context resets or
deletes all its direct and indirect children as well. This feature allows
us to manage a lot of contexts without fear that some will be leaked; we
only need to keep track of one top-level context that we are going to
delete at transaction end, and make sure that any shorter-lived contexts
we create are descendants of that context. Since the tree can have
multiple levels, we can deal easily with nested lifetimes of storage,
such as per-transaction, per-statement, per-scan, per-tuple. Storage
lifetimes that only partially overlap can be handled by allocating
from different trees of the context forest (there are some examples
in the next section).
For convenience we will also want operations like "reset/delete all
children of a given context, but don't reset or delete that context
itself".
Top-level contexts
------------------
There will be several top-level contexts --- these contexts have no parent
and will be referenced by global variables. At any instant the system may
contain many additional contexts, but all other contexts should be direct
or indirect children of one of the top-level contexts to ensure they are
not leaked in event of an error. I presently envision these top-level
contexts:
TopMemoryContext --- allocating here is essentially the same as "malloc",
because this context will never be reset or deleted. This is for stuff
that should live forever, or for stuff that you know you will delete
at the appropriate time. An example is fd.c's tables of open files,
as well as the context management nodes for memory contexts themselves.
Avoid allocating stuff here unless really necessary, and especially
avoid running with CurrentMemoryContext pointing here.
PostmasterContext --- this is the postmaster's normal working context.
After a backend is spawned, it can delete PostmasterContext to free its
copy of memory the postmaster was using that it doesn't need. (Anything
that has to be passed from postmaster to backends will be passed in
TopMemoryContext. The postmaster will probably have only TopMemoryContext,
PostmasterContext, and possibly ErrorContext --- the remaining top-level
contexts will be set up in each backend during startup.)
CacheMemoryContext --- permanent storage for relcache, catcache, and
related modules. This will never be reset or deleted, either, so it's
not truly necessary to distinguish it from TopMemoryContext. But it
seems worthwhile to maintain the distinction for debugging purposes.
(Note: CacheMemoryContext may well have child-contexts with shorter
lifespans. For example, a child context seems like the best place to
keep the subsidiary storage associated with a relcache entry; that way
we can free rule parsetrees and so forth easily, without having to depend
on constructing a reliable version of freeObject().)
QueryContext --- this is where the storage holding a received query string
is kept, as well as storage that should live as long as the query string,
notably the parsetree constructed from it. This context will be reset at
the top of each cycle of the outer loop of PostgresMain, thereby freeing
the old query and parsetree. We must keep this separate from
TopTransactionContext because a query string might need to live either a
longer or shorter time than a transaction, depending on whether it
contains begin/end commands or not. (This'll also fix the nasty bug that
"vacuum; anything else" crashes if submitted as a single query string,
because vacuum's xact commit frees the memory holding the parsetree...)
TopTransactionContext --- this holds everything that lives until end of
transaction (longer than one statement within a transaction!). An example
of what has to be here is the list of pending NOTIFY messages to be sent
at xact commit. This context will be reset, and all its children deleted,
at conclusion of each transaction cycle. Note: presently I envision that
this context will NOT be cleared immediately upon error; its contents
will survive anyway until the transaction block is exited by
COMMIT/ROLLBACK. This seems appropriate since we want to move in the
direction of allowing a transaction to continue processing after an error.
TransactionCommandContext --- this is really a child of
TopTransactionContext, not a top-level context, but we'll probably store a
link to it in a global variable anyway for convenience. All the memory
allocated during planning and execution lives here or in a child context.
This context is deleted at statement completion, whether normal completion
or error abort.
ErrorContext --- this permanent context will be switched into
for error recovery processing, and then reset on completion of recovery.
We'll arrange to have, say, 8K of memory available in it at all times.
In this way, we can ensure that some memory is available for error
recovery even if the backend has run out of memory otherwise. This should
allow out-of-memory to be treated as a normal ERROR condition, not a FATAL
error.
If we ever implement nested transactions, there may need to be some
additional levels of transaction-local contexts between
TopTransactionContext and TransactionCommandContext, but that's beyond
the scope of this proposal.
Transient contexts during execution
-----------------------------------
The planner will probably have a transient context in which it stores
pathnodes; this will allow it to release the bulk of its temporary space
usage (which can be a lot, for large joins) at completion of planning.
The completed plan tree will be in TransactionCommandContext.
The executor will have contexts with lifetime similar to plan nodes
(I'm not sure at the moment whether there's need for one such context
per plan level, or whether a single context is sufficient). These
contexts will hold plan-node-local execution state and related items.
There will also be a context on each plan level that is reset at the start
of each tuple processing cycle. This per-tuple context will be the normal
CurrentMemoryContext during evaluation of expressions and so forth. By
resetting it, we reclaim transient memory that was used during processing
of the prior tuple. That should be enough to solve the problem of running
out of memory on large queries. We must have a per-tuple context in each
plan node, and we must reset it at the start of a tuple cycle rather than
the end, so that each plan node can use results of expression evaluation
as part of the tuple it returns to its parent node.
By resetting the per-tuple context, we will be able to free memory after
each tuple is processed, rather than only after the whole plan is
processed. This should solve our memory leakage problems pretty well;
yet we do not need to add very much new bookkeeping logic to do it.
In particular, we do *not* need to try to keep track of individual values
palloc'd during expression evaluation.
Note we assume that resetting a context is a cheap operation. This is
true already, and we can make it even more true with a little bit of
tuning in aset.c.
There will be some special cases, such as aggregate functions. nodeAgg.c
needs to remember the results of evaluation of aggregate transition
functions from one tuple cycle to the next, so it can't just discard
all per-tuple state in each cycle. The easiest way to handle this seems
to be to have two per-tuple contexts in an aggregate node, and to
ping-pong between them, so that at each tuple one is the active allocation
context and the other holds any results allocated by the prior cycle's
transition function.
Executor routines that switch the active CurrentMemoryContext may need
to copy data into their caller's current memory context before returning.
I think there will be relatively little need for that, because of the
convention of resetting the per-tuple context at the *start* of an
execution cycle rather than at its end. With that rule, an execution
node can return a tuple that is palloc'd in its per-tuple context, and
the tuple will remain good until the node is called for another tuple
or told to end execution. This is pretty much the same state of affairs
that exists now, since a scan node can return a direct pointer to a tuple
in a disk buffer that is only guaranteed to remain good that long.
A more common reason for copying data will be to transfer a result from
per-tuple context to per-run context; for example, a Unique node will
save the last distinct tuple value in its per-run context, requiring a
copy step. (Actually, Unique could use the same trick with two per-tuple
contexts as described above for Agg, but there will probably be other
cases where doing an extra copy step is the right thing.)
Another interesting special case is VACUUM, which needs to allocate
working space that will survive its forced transaction commits, yet
be released on error. Currently it does that through a "portal",
which is essentially a child context of TopMemoryContext. While that
way still works, it's ugly since xact abort needs special processing
to delete the portal. Better would be to use a context that's a child
of QueryContext and hence is certain to go away as part of normal
processing. (Eventually we might have an even better solution from
nested transactions, but this'll do fine for now.)
Mechanisms to allow multiple types of contexts
----------------------------------------------
We may want several different types of memory contexts with different
allocation policies but similar external behavior. To handle this,
memory allocation functions will be accessed via function pointers,
and we will require all context types to obey the conventions given here.
(This is not very far different from the existing code.)
A memory context will be represented by an object like
typedef struct MemoryContextData
{
NodeTag type; /* identifies exact kind of context */
MemoryContextMethods methods;
MemoryContextData *parent; /* NULL if no parent (toplevel context) */
MemoryContextData *firstchild; /* head of linked list of children */
MemoryContextData *nextchild; /* next child of same parent */
char *name; /* context name (just for debugging) */
} MemoryContextData, *MemoryContext;
This is essentially an abstract superclass, and the "methods" pointer is
its virtual function table. Specific memory context types will use
derived structs having these fields as their first fields. All the
contexts of a specific type will have methods pointers that point to the
same static table of function pointers, which will look like
typedef struct MemoryContextMethodsData
{
Pointer (*alloc) (MemoryContext c, Size size);
void (*free_p) (Pointer chunk);
Pointer (*realloc) (Pointer chunk, Size newsize);
void (*reset) (MemoryContext c);
void (*delete) (MemoryContext c);
} MemoryContextMethodsData, *MemoryContextMethods;
Alloc, reset, and delete requests will take a MemoryContext pointer
as parameter, so they'll have no trouble finding the method pointer
to call. Free and realloc are trickier. To make those work, we will
require all memory context types to produce allocated chunks that
are immediately preceded by a standard chunk header, which has the
layout
typedef struct StandardChunkHeader
{
MemoryContext mycontext; /* Link to owning context object */
Size size; /* Allocated size of chunk */
};
It turns out that the existing aset.c memory context type does this
already, and probably any other kind of context would need to have the
same data available to support realloc, so this is not really creating
any additional overhead. (Note that if a context type needs more per-
allocated-chunk information than this, it can make an additional
nonstandard header that precedes the standard header. So we're not
constraining context-type designers very much.)
Given this, the pfree routine will look something like
StandardChunkHeader * header =
(StandardChunkHeader *) ((char *) p - sizeof(StandardChunkHeader));
(*header->mycontext->methods->free_p) (p);
We could do it as a macro, but the macro would have to evaluate its
argument twice, which seems like a bad idea (the current pfree macro
does not do that). This is already saving two levels of function call
compared to the existing code, so I think we're doing fine without
squeezing out that last little bit ...
More control over aset.c behavior
---------------------------------
Currently, aset.c allocates an 8K block upon the first allocation in
a context, and doubles that size for each successive block request.
That's good behavior for a context that might hold *lots* of data, and
the overhead wasn't bad when we had only a few contexts in existence.
With dozens if not hundreds of smaller contexts in the system, we will
want to be able to fine-tune things a little better.
The creator of a context will be able to specify an initial block size
and a maximum block size. Selecting smaller values will prevent wastage
of space in contexts that aren't expected to hold very much (an example is
the relcache's per-relation contexts).
Also, it will be possible to specify a minimum context size. If this
value is greater than zero then a block of that size will be grabbed
immediately upon context creation, and cleared but not released during
context resets. This feature is needed for ErrorContext (see above).
It is also useful for per-tuple contexts, which will be reset frequently
and typically will not allocate very much space per tuple cycle. We can
save a lot of unnecessary malloc traffic if these contexts hang onto one
allocation block rather than releasing and reacquiring the block on
each tuple cycle.
Other notes
-----------
The original version of this proposal suggested that functions returning
pass-by-reference datatypes should be required to return a value freshly
palloc'd in their caller's memory context, never a pointer to an input
value. I've abandoned that notion since it clearly is prone to error.
In the current proposal, it is possible to discover which context a
chunk of memory is allocated in (by checking the required standard chunk
header), so nodeAgg can determine whether or not it's safe to reset
its working context; it doesn't have to rely on the transition function
to do what it's expecting.
It might be that the executor per-run contexts described above should
be tied directly to executor "EState" nodes, that is, one context per
EState. I'm not real clear on the lifespan of EStates or the situations
where we have just one or more than one, so I'm not sure. Comments?
It would probably be possible to adapt the existing "portal" memory
management mechanism to do what we need. I am instead proposing setting
up a totally new mechanism, because the portal code strikes me as
extremely crufty and unwieldy. It may be that we can eventually remove
portals entirely, or perhaps reimplement them with this mechanism
underneath.

View File

@ -3,12 +3,15 @@
* aset.c
* Allocation set definitions.
*
* AllocSet is our standard implementation of the abstract MemoryContext
* type.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.27 2000/05/21 02:23:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.28 2000/06/28 03:32:50 tgl Exp $
*
* NOTE:
* This is a new (Feb. 05, 1999) implementation of the allocation set
@ -30,15 +33,68 @@
* AllocSetReset() under the old way.
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/memutils.h"
#undef AllocSetReset
#undef malloc
#undef free
#undef realloc
/*
* AllocSetContext is defined in nodes/memnodes.h.
*/
typedef AllocSetContext *AllocSet;
/*
* AllocPointer
* Aligned pointer which may be a member of an allocation set.
*/
typedef void *AllocPointer;
/*
* AllocBlock
* An AllocBlock is the unit of memory that is obtained by aset.c
* from malloc(). It contains one or more AllocChunks, which are
* the units requested by palloc() and freed by pfree(). AllocChunks
* cannot be returned to malloc() individually, instead they are put
* on freelists by pfree() and re-used by the next palloc() that has
* a matching request size.
*
* AllocBlockData is the header data for a block --- the usable space
* within the block begins at the next alignment boundary.
*/
typedef struct AllocBlockData
{
AllocSet aset; /* aset that owns this block */
AllocBlock next; /* next block in aset's blocks list */
char *freeptr; /* start of free space in this block */
char *endptr; /* end of space in this block */
} AllocBlockData;
/*
* AllocChunk
* The prefix of each piece of memory in an AllocBlock
*
* NB: this MUST match StandardChunkHeader as defined by utils/memutils.h.
*/
typedef struct AllocChunkData
{
/* aset is the owning aset if allocated, or the freelist link if free */
void *aset;
/* size is always the size of the usable space in the chunk */
Size size;
} AllocChunkData;
/*
* AllocPointerIsValid
* True iff pointer is valid allocation pointer.
*/
#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
/*
* AllocSetIsValid
* True iff set is valid allocation set.
*/
#define AllocSetIsValid(set) PointerIsValid(set)
/*--------------------
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
@ -59,9 +115,9 @@
/* Size of largest chunk that we use a fixed size for */
/*--------------------
* The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
* The first block allocated for an allocset has size initBlockSize.
* Each time we have to allocate another block, we double the block size
* (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
* (if possible, and without exceeding maxBlockSize), so as to reduce
* the bookkeeping load on malloc().
*
* Blocks allocated to hold oversize chunks do not follow this rule, however;
@ -74,20 +130,21 @@
* AllocSetAlloc has discretion whether to put the request into an existing
* block or make a single-chunk block.
*
* We must have ALLOC_MIN_BLOCK_SIZE > ALLOC_SMALLCHUNK_LIMIT and
* We must have initBlockSize > ALLOC_SMALLCHUNK_LIMIT and
* ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
*--------------------
*/
#define ALLOC_MIN_BLOCK_SIZE (8 * 1024)
#define ALLOC_MAX_BLOCK_SIZE (8 * 1024 * 1024)
#define ALLOC_BIGCHUNK_LIMIT (64 * 1024)
/* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
/* Min safe value of allocation block size */
#define ALLOC_MIN_BLOCK_SIZE \
(ALLOC_SMALLCHUNK_LIMIT + ALLOC_CHUNKHDRSZ + ALLOC_BLOCKHDRSZ)
#define AllocPointerGetChunk(ptr) \
((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
#define AllocChunkGetPointer(chk) \
@ -95,6 +152,29 @@
#define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
#define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size)
/*
* These functions implement the MemoryContext API for AllocSet contexts.
*/
static void *AllocSetAlloc(MemoryContext context, Size size);
static void AllocSetFree(MemoryContext context, void *pointer);
static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
static void AllocSetInit(MemoryContext context);
static void AllocSetReset(MemoryContext context);
static void AllocSetDelete(MemoryContext context);
static void AllocSetStats(MemoryContext context);
/*
* This is the virtual function table for AllocSet contexts.
*/
static MemoryContextMethods AllocSetMethods = {
AllocSetAlloc,
AllocSetFree,
AllocSetRealloc,
AllocSetInit,
AllocSetReset,
AllocSetDelete,
AllocSetStats
};
/* ----------
@ -127,52 +207,159 @@ AllocSetFreeIndex(Size size)
* Public routines
*/
/*
* AllocSetInit
* Initializes given allocation set.
* AllocSetContextCreate
* Create a new AllocSet context.
*
* Note:
* The semantics of the mode are explained above. Limit is ignored
* for dynamic and static modes.
*
* Exceptions:
* BadArg if set is invalid pointer.
* BadArg if mode is invalid.
* parent: parent context, or NULL if top-level context
* name: name of context (for debugging --- string will be copied)
* minContextSize: minimum context size
* initBlockSize: initial allocation block size
* maxBlockSize: maximum allocation block size
*/
void
AllocSetInit(AllocSet set, AllocMode mode, Size limit)
MemoryContext
AllocSetContextCreate(MemoryContext parent,
const char *name,
Size minContextSize,
Size initBlockSize,
Size maxBlockSize)
{
AssertArg(PointerIsValid(set));
AssertArg((int) DynamicAllocMode <= (int) mode);
AssertArg((int) mode <= (int) BoundedAllocMode);
AllocSet context;
/* Do the type-independent part of context creation */
context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
sizeof(AllocSetContext),
&AllocSetMethods,
parent,
name);
/*
* Make sure alloc parameters are safe, and save them
*/
initBlockSize = MAXALIGN(initBlockSize);
if (initBlockSize < ALLOC_MIN_BLOCK_SIZE)
initBlockSize = ALLOC_MIN_BLOCK_SIZE;
maxBlockSize = MAXALIGN(maxBlockSize);
if (maxBlockSize < initBlockSize)
maxBlockSize = initBlockSize;
context->initBlockSize = initBlockSize;
context->maxBlockSize = maxBlockSize;
/*
* XXX mode is currently ignored and treated as DynamicAllocMode. XXX
* limit is also ignored. This affects this whole file.
* Grab always-allocated space, if requested
*/
if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)
{
Size blksize = MAXALIGN(minContextSize);
AllocBlock block;
memset(set, 0, sizeof(AllocSetData));
block = (AllocBlock) malloc(blksize);
if (block == NULL)
elog(ERROR, "Memory exhausted in AllocSetContextCreate()");
block->aset = context;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize;
block->next = context->blocks;
context->blocks = block;
/* Mark block as not to be released at reset time */
context->keeper = block;
}
return (MemoryContext) context;
}
/*
* AllocSetInit
* Context-type-specific initialization routine.
*
* This is called by MemoryContextCreate() after setting up the
* generic MemoryContext fields and before linking the new context
* into the context tree. We must do whatever is needed to make the
* new context minimally valid for deletion. We must *not* risk
* failure --- thus, for example, allocating more memory is not cool.
* (AllocSetContextCreate can allocate memory when it gets control
* back, however.)
*/
static void
AllocSetInit(MemoryContext context)
{
/*
* Since MemoryContextCreate already zeroed the context node,
* we don't have to do anything here: it's already OK.
*/
}
/*
* AllocSetReset
* Frees all memory which is allocated in the given set.
*
* Exceptions:
* BadArg if set is invalid.
* Actually, this routine has some discretion about what to do.
* It should mark all allocated chunks freed, but it need not
* necessarily give back all the resources the set owns. Our
* actual implementation is that we hang on to any "keeper"
* block specified for the set.
*/
void
AllocSetReset(AllocSet set)
static void
AllocSetReset(MemoryContext context)
{
AllocSet set = (AllocSet) context;
AllocBlock block = set->blocks;
AllocBlock next;
AssertArg(AllocSetIsValid(set));
while (block != NULL)
{
next = block->next;
AllocBlock next = block->next;
if (block == set->keeper)
{
/* Reset the block, but don't return it to malloc */
block->next = NULL;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
#ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */
memset(block->freeptr, 0x7F,
((char *) block->endptr) - ((char *) block->freeptr));
#endif
}
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;
}
/* 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));
}
/*
* AllocSetDelete
* Frees all memory which is allocated in the given set,
* in preparation for deletion of the set.
*
* Unlike AllocSetReset, this *must* free all resources of the set.
* But note we are not responsible for deleting the context node itself.
*/
static void
AllocSetDelete(MemoryContext context)
{
AllocSet set = (AllocSet) context;
AllocBlock block = set->blocks;
AssertArg(AllocSetIsValid(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));
@ -181,38 +368,21 @@ AllocSetReset(AllocSet set)
block = next;
}
memset(set, 0, sizeof(AllocSetData));
}
/*
* AllocSetContains
* True iff allocation set contains given allocation element.
*
* Exceptions:
* BadArg if set is invalid.
* BadArg if pointer is invalid.
*/
bool
AllocSetContains(AllocSet set, AllocPointer pointer)
{
AssertArg(AllocSetIsValid(set));
AssertArg(AllocPointerIsValid(pointer));
return (AllocPointerGetAset(pointer) == set);
/* Make it look empty, just in case... */
set->blocks = NULL;
MemSet(set->freelist, 0, sizeof(set->freelist));
set->keeper = NULL;
}
/*
* AllocSetAlloc
* Returns pointer to allocated memory of given size; memory is added
* to the set.
*
* Exceptions:
* BadArg if set is invalid.
* MemoryExhausted if allocation fails.
*/
AllocPointer
AllocSetAlloc(AllocSet set, Size size)
static void *
AllocSetAlloc(MemoryContext context, Size size)
{
AllocSet set = (AllocSet) context;
AllocBlock block;
AllocChunk chunk;
AllocChunk priorfree = NULL;
@ -225,7 +395,6 @@ AllocSetAlloc(AllocSet set, Size size)
/*
* Lookup in the corresponding free list if there is a free chunk we
* could reuse
*
*/
fidx = AllocSetFreeIndex(size);
for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
@ -238,7 +407,6 @@ AllocSetAlloc(AllocSet set, Size size)
/*
* If one is found, remove it from the free list, make it again a
* member of the alloc set and return its data address.
*
*/
if (chunk != NULL)
{
@ -284,7 +452,7 @@ AllocSetAlloc(AllocSet set, Size size)
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
block = (AllocBlock) malloc(blksize);
if (block == NULL)
elog(FATAL, "Memory exhausted in AllocSetAlloc()");
elog(ERROR, "Memory exhausted in AllocSetAlloc()");
block->aset = set;
block->freeptr = block->endptr = ((char *) block) + blksize;
@ -317,7 +485,7 @@ AllocSetAlloc(AllocSet set, Size size)
{
if (set->blocks == NULL)
{
blksize = ALLOC_MIN_BLOCK_SIZE;
blksize = set->initBlockSize;
block = (AllocBlock) malloc(blksize);
}
else
@ -327,15 +495,18 @@ AllocSetAlloc(AllocSet set, Size size)
/*
* Special case: if very first allocation was for a large
* chunk, could have a funny-sized top block. Do something
* reasonable.
* chunk (or we have a small "keeper" block), could have an
* undersized top block. Do something reasonable.
*/
if (blksize < ALLOC_MIN_BLOCK_SIZE)
blksize = ALLOC_MIN_BLOCK_SIZE;
/* Crank it up, but not past max */
blksize <<= 1;
if (blksize > ALLOC_MAX_BLOCK_SIZE)
blksize = ALLOC_MAX_BLOCK_SIZE;
if (blksize < set->initBlockSize)
blksize = set->initBlockSize;
else
{
/* Crank it up, but not past max */
blksize <<= 1;
if (blksize > set->maxBlockSize)
blksize = set->maxBlockSize;
}
/* Try to allocate it */
block = (AllocBlock) malloc(blksize);
@ -352,7 +523,7 @@ AllocSetAlloc(AllocSet set, Size size)
}
if (block == NULL)
elog(FATAL, "Memory exhausted in AllocSetAlloc()");
elog(ERROR, "Memory exhausted in AllocSetAlloc()");
block->aset = set;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize;
@ -376,22 +547,12 @@ AllocSetAlloc(AllocSet set, Size size)
/*
* AllocSetFree
* Frees allocated memory; memory is removed from the set.
*
* Exceptions:
* BadArg if set is invalid.
* BadArg if pointer is invalid.
* BadArg if pointer is not member of set.
*/
void
AllocSetFree(AllocSet set, AllocPointer pointer)
static void
AllocSetFree(MemoryContext context, void *pointer)
{
AllocChunk chunk;
/* AssertArg(AllocSetIsValid(set)); */
/* AssertArg(AllocPointerIsValid(pointer)); */
AssertArg(AllocSetContains(set, pointer));
chunk = AllocPointerGetChunk(pointer);
AllocSet set = (AllocSet) context;
AllocChunk chunk = AllocPointerGetChunk(pointer);
#ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */
@ -446,24 +607,15 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
* Returns new pointer to allocated memory of given size; this memory
* is added to the set. Memory associated with given pointer is copied
* into the new memory, and the old memory is freed.
*
* Exceptions:
* BadArg if set is invalid.
* BadArg if pointer is invalid.
* BadArg if pointer is not member of set.
* MemoryExhausted if allocation fails.
*/
AllocPointer
AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
static void *
AllocSetRealloc(MemoryContext context, void *pointer, Size size)
{
AllocSet set = (AllocSet) context;
Size oldsize;
/* AssertArg(AllocSetIsValid(set)); */
/* AssertArg(AllocPointerIsValid(pointer)); */
AssertArg(AllocSetContains(set, pointer));
/*
* Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
* Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
* allocated area already is >= the new size. (In particular, we
* always fall out here if the requested size is a decrease.)
*/
@ -503,7 +655,7 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
block = (AllocBlock) realloc(block, blksize);
if (block == NULL)
elog(FATAL, "Memory exhausted in AllocSetReAlloc()");
elog(ERROR, "Memory exhausted in AllocSetReAlloc()");
block->freeptr = block->endptr = ((char *) block) + blksize;
/* Update pointers since block has likely been moved */
@ -520,35 +672,26 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
/* Normal small-chunk case: just do it by brute force. */
/* allocate new chunk */
AllocPointer newPointer = AllocSetAlloc(set, size);
AllocPointer newPointer = AllocSetAlloc((MemoryContext) set, size);
/* transfer existing data (certain to fit) */
memcpy(newPointer, pointer, oldsize);
/* free old chunk */
AllocSetFree(set, pointer);
AllocSetFree((MemoryContext) set, pointer);
return newPointer;
}
}
/*
* AllocSetDump
* Displays allocated set.
*/
void
AllocSetDump(AllocSet set)
{
elog(DEBUG, "Currently unable to dump AllocSet");
}
/*
* AllocSetStats
* Displays stats about memory consumption of an allocset.
*/
void
AllocSetStats(AllocSet set, const char *ident)
static void
AllocSetStats(MemoryContext context)
{
AllocSet set = (AllocSet) context;
long nblocks = 0;
long nchunks = 0;
long totalspace = 0;
@ -557,8 +700,6 @@ AllocSetStats(AllocSet set, const char *ident)
AllocChunk chunk;
int fidx;
AssertArg(AllocSetIsValid(set));
for (block = set->blocks; block != NULL; block = block->next)
{
nblocks++;
@ -576,6 +717,6 @@ AllocSetStats(AllocSet set, const char *ident)
}
fprintf(stderr,
"%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n",
ident, totalspace, nblocks, freespace, nchunks,
set->header.name, totalspace, nblocks, freespace, nchunks,
totalspace - freespace);
}

View File

@ -1,14 +1,20 @@
/*-------------------------------------------------------------------------
*
* mcxt.c
* POSTGRES memory context code.
* POSTGRES memory context management code.
*
* This module handles context management operations that are independent
* of the particular kind of context being operated on. It calls
* context-type-specific operations via the function pointers in a
* context's MemoryContextMethods struct.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.21 2000/05/21 02:23:29 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.22 2000/06/28 03:32:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,323 +23,440 @@
#include "nodes/memnodes.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 *
*****************************************************************************/
/*
* CurrentMemoryContext
* Memory context for general global allocations.
* Default memory context for allocations.
*/
DLLIMPORT MemoryContext CurrentMemoryContext = NULL;
/*
* 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;
/*****************************************************************************
* PRIVATE DEFINITIONS *
* EXPORTED ROUTINES *
*****************************************************************************/
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
*/
static struct MemoryContextMethodsData GlobalContextMethodsData = {
GlobalMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
GlobalMemoryFree, /* void (*)(this, Pointer) pfree */
GlobalMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
GlobalMemoryGetName, /* char* (*)(this) getName */
GlobalMemoryDump /* void (*)(this) dump */
};
/*
* Note:
* TopGlobalMemory is handled specially because of bootstrapping.
*/
/* extern bool EqualGlobalMemory(); */
static struct GlobalMemoryData TopGlobalMemoryData = {
T_GlobalMemory, /* NodeTag tag */
&GlobalContextMethodsData, /* ContextMethods method */
{NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
/* free AllocSet */
"TopGlobal", /* char* name */
{0} /* uninitialized OrderedElemData elemD */
};
/*
* TopMemoryContext
* Memory context for general global allocations.
* MemoryContextInit
* Start up the memory-context subsystem.
*
* Note:
* Don't use this memory context for random allocations. If you
* allocate something here, you are expected to clean it up when
* appropriate.
*/
MemoryContext TopMemoryContext = (MemoryContext) &TopGlobalMemoryData;
/*
* Module State
*/
/*
* EnableMemoryContext
* Enables/disables memory management and global contexts.
* This must be called before creating contexts or allocating memory in
* contexts. TopMemoryContext and ErrorContext are initialized here;
* other contexts must be created afterwards.
*
* Note:
* This must be called before creating contexts or allocating memory.
* This must be called before other contexts are created.
* In normal multi-backend operation, this is called once during
* postmaster startup, and not at all by individual backend startup
* (since the backends inherit an already-initialized context subsystem
* by virtue of being forked off the postmaster).
*
* Exceptions:
* BadArg if on is invalid.
* BadState if on is false when disabled.
* In a standalone backend this must be called during backend startup.
*/
void
EnableMemoryContext(bool on)
MemoryContextInit(void)
{
static bool processing = false;
AssertState(TopMemoryContext == NULL);
/*
* Initialize TopMemoryContext as an AllocSetContext with slow
* growth rate --- we don't really expect much to be allocated in it.
*
* (There is special-case code in MemoryContextCreate() for this call.)
*/
TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
"TopMemoryContext",
8 * 1024,
8 * 1024,
8 * 1024);
/*
* Not having any other place to point CurrentMemoryContext,
* make it point to TopMemoryContext. Caller should change this soon!
*/
CurrentMemoryContext = TopMemoryContext;
/*
* Initialize ErrorContext as an AllocSetContext with slow
* growth rate --- we don't really expect much to be allocated in it.
* More to the point, require it to contain at least 8K at all times.
* This is the only case where retained memory in a context is
* *essential* --- we want to be sure ErrorContext still has some
* memory even if we've run out elsewhere!
*/
ErrorContext = AllocSetContextCreate(TopMemoryContext,
"ErrorContext",
8 * 1024,
8 * 1024,
8 * 1024);
}
AssertState(!processing);
AssertArg(BoolIsValid(on));
/*
* MemoryContextReset
* Release all space allocated within a context and its descendants,
* but don't delete the contexts themselves.
*
* The type-specific reset routine handles the context itself, but we
* have to do the recursion for the children.
*/
void
MemoryContextReset(MemoryContext context)
{
MemoryContextResetChildren(context);
(*context->methods->reset) (context);
}
if (BypassEnable(&MemoryContextEnableCount, on))
return;
/*
* MemoryContextResetChildren
* Release all space allocated within a context's descendants,
* but don't delete the contexts themselves. The named context
* itself is not touched.
*/
void
MemoryContextResetChildren(MemoryContext context)
{
MemoryContext child;
processing = true;
for (child = context->firstchild; child != NULL; child = child->nextchild)
{
MemoryContextReset(child);
}
}
if (on)
{ /* initialize */
/* initialize TopGlobalMemoryData.setData */
AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
(Size) 0);
/*
* MemoryContextDelete
* Delete a context and its descendants, and release all space
* allocated therein.
*
* The type-specific delete routine removes all subsidiary storage
* for the context, but we have to delete the context node itself,
* as well as recurse to get the children. We must also delink the
* node from its parent, if it has one.
*/
void
MemoryContextDelete(MemoryContext context)
{
/* We had better not be deleting TopMemoryContext ... */
Assert(context != TopMemoryContext);
/* And not CurrentMemoryContext, either */
Assert(context != CurrentMemoryContext);
/* make TopGlobalMemoryData member of ActiveGlobalMemorySet */
OrderedSetInit(ActiveGlobalMemorySet,
offsetof(struct GlobalMemoryData, elemData));
OrderedElemPushInto(&TopGlobalMemoryData.elemData,
ActiveGlobalMemorySet);
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;
/* initialize CurrentMemoryContext */
CurrentMemoryContext = TopMemoryContext;
if (context == parent->firstchild)
{
parent->firstchild = context->nextchild;
}
else
{
MemoryContext child;
for (child = parent->firstchild; child; child = child->nextchild)
{
if (context == child->nextchild)
{
child->nextchild = context->nextchild;
break;
}
}
}
}
(*context->methods->delete) (context);
pfree(context);
}
/*
* MemoryContextDeleteChildren
* Delete all the descendants of the named context and release all
* space allocated therein. The named context itself is not touched.
*/
void
MemoryContextDeleteChildren(MemoryContext context)
{
/*
* MemoryContextDelete will delink the child from me,
* so just iterate as long as there is a child.
*/
while (context->firstchild != NULL)
{
MemoryContextDelete(context->firstchild);
}
}
/*
* MemoryContextResetAndDeleteChildren
* Release all space allocated within a context and delete all
* its descendants.
*
* This is a common combination case where we want to preserve the
* specific context but get rid of absolutely everything under it.
*/
void
MemoryContextResetAndDeleteChildren(MemoryContext context)
{
MemoryContextDeleteChildren(context);
(*context->methods->reset) (context);
}
/*
* MemoryContextStats
* Print statistics about the named context and all its descendants.
*
* This is just a debugging utility, so it's not fancy. The statistics
* are merely sent to stderr.
*/
void
MemoryContextStats(MemoryContext context)
{
MemoryContext child;
(*context->methods->stats) (context);
for (child = context->firstchild; child != NULL; child = child->nextchild)
{
MemoryContextStats(child);
}
}
/*
* MemoryContextContains
* Detect whether an allocated chunk of memory belongs to a given
* context or not.
*
* Caution: this test is reliable as long as 'pointer' does point to
* a chunk of memory allocated from *some* context. If 'pointer' points
* at memory obtained in some other way, there is a small chance of a
* false-positive result, since the bits right before it might look like
* a valid chunk header by chance.
*/
bool
MemoryContextContains(MemoryContext context, void *pointer)
{
StandardChunkHeader *header;
/*
* Try to detect bogus pointers handed to us, poorly though we can.
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at
* an allocated chunk.
*/
if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
return false;
/*
* OK, it's probably safe to look at the chunk header.
*/
header = (StandardChunkHeader *)
((char *) pointer - STANDARDCHUNKHEADERSIZE);
/*
* If the context link doesn't match then we certainly have a
* non-member chunk. Also check for a reasonable-looking size
* as extra guard against being fooled by bogus pointers.
*/
if (header->context == context && AllocSizeIsValid(header->size))
return true;
return false;
}
/*--------------------
* MemoryContextCreate
* Context-type-independent part of context creation.
*
* This is only intended to be called by context-type-specific
* context creation routines, not by the unwashed masses.
*
* The context creation procedure is a little bit tricky because
* we want to be sure that we don't leave the context tree invalid
* in case of failure (such as insufficient memory to allocate the
* context node itself). The procedure goes like this:
* 1. Context-type-specific routine first calls MemoryContextCreate(),
* passing the appropriate tag/size/methods values (the methods
* pointer will ordinarily point to statically allocated data).
* The parent and name parameters usually come from the caller.
* 2. MemoryContextCreate() attempts to allocate the context node,
* plus space for the name. If this fails we can elog() with no
* damage done.
* 3. We fill in all of the type-independent MemoryContext fields.
* 4. We call the type-specific init routine (using the methods pointer).
* The init routine is required to make the node minimally valid
* with zero chance of failure --- it can't allocate more memory,
* for example.
* 5. Now we have a minimally valid node that can behave correctly
* when told to reset or delete itself. We link the node to its
* parent (if any), making the node part of the context tree.
* 6. We return to the context-type-specific routine, which finishes
* up type-specific initialization. This routine can now do things
* that might fail (like allocate more memory), so long as it's
* sure the node is left in a state that delete will handle.
*
* This protocol doesn't prevent us from leaking memory if step 6 fails
* during creation of a top-level context, since there's no parent link
* in that case. However, if you run out of memory while you're building
* a top-level context, you might as well go home anyway...
*
* Normally, the context node and the name are allocated from
* TopMemoryContext (NOT from the parent context, since the node must
* survive resets of its parent context!). However, this routine is itself
* used to create TopMemoryContext! If we see that TopMemoryContext is NULL,
* we assume we are creating TopMemoryContext and use malloc() to allocate
* the node.
*
* Note that the name field of a MemoryContext does not point to
* separately-allocated storage, so it should not be freed at context
* deletion.
*--------------------
*/
MemoryContext
MemoryContextCreate(NodeTag tag, Size size,
MemoryContextMethods *methods,
MemoryContext parent,
const char *name)
{
MemoryContext node;
Size needed = size + strlen(name) + 1;
/* Get space for node and name */
if (TopMemoryContext != NULL)
{
/* Normal case: allocate the node in TopMemoryContext */
node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
needed);
}
else
{ /* cleanup */
GlobalMemory context;
/* walk the list of allocations */
while (PointerIsValid(context = (GlobalMemory)
OrderedSetGetHead(ActiveGlobalMemorySet)))
{
if (context == &TopGlobalMemoryData)
{
/* don't free it and clean it last */
OrderedElemPop(&TopGlobalMemoryData.elemData);
}
else
GlobalMemoryDestroy(context);
/* what is needed for the top? */
}
/*
* Freeing memory here should be safe as this is called only after
* all modules which allocate in TopMemoryContext have been
* disabled.
*/
/* step through remaining allocations and log */
/* AllocSetStep(...); */
/* deallocate whatever is left */
AllocSetReset(&TopGlobalMemoryData.setData);
{
/* Special case for startup: use good ol' malloc */
node = (MemoryContext) malloc(needed);
Assert(node != NULL);
}
processing = false;
/* Initialize the node as best we can */
MemSet(node, 0, size);
node->type = tag;
node->methods = methods;
node->parent = NULL; /* for the moment */
node->firstchild = NULL;
node->nextchild = NULL;
node->name = ((char *) node) + size;
strcpy(node->name, name);
/* Type-specific routine finishes any other essential initialization */
(*node->methods->init) (node);
/* OK to link node to parent (if any) */
if (parent)
{
node->parent = parent;
node->nextchild = parent->firstchild;
parent->firstchild = node;
}
/* Return to type-specific creation routine to finish up */
return node;
}
/*
* MemoryContextAlloc
* Returns pointer to aligned allocated memory in the given context.
* Allocate space within the specified context.
*
* Note:
* none
*
* Exceptions:
* BadState if called before InitMemoryManager.
* BadArg if context is invalid or if size is 0.
* BadAllocSize if size is larger than MaxAllocSize.
* This could be turned into a macro, but we'd have to import
* nodes/memnodes.h into postgres.h which seems a bad idea.
*/
Pointer
void *
MemoryContextAlloc(MemoryContext context, Size size)
{
AssertState(MemoryContextEnabled);
AssertArg(MemoryContextIsValid(context));
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
("size=%d [0x%x]", size, size));
return context->method->alloc(context, size);
return (*context->methods->alloc) (context, size);
}
/*
* MemoryContextFree
* Frees allocated memory referenced by pointer in the given context.
*
* Note:
* none
*
* Exceptions:
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
* pfree
* Release an allocated chunk.
*/
void
MemoryContextFree(MemoryContext context, Pointer pointer)
pfree(void *pointer)
{
AssertState(MemoryContextEnabled);
AssertArg(MemoryContextIsValid(context));
AssertArg(PointerIsValid(pointer));
StandardChunkHeader *header;
context->method->free_p(context, pointer);
/*
* 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);
}
/*
* MemoryContextRelloc
* Returns pointer to aligned allocated memory in the given context.
* repalloc
*
* Note:
* none
*
* Exceptions:
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
*/
Pointer
MemoryContextRealloc(MemoryContext context,
Pointer pointer,
Size size)
void *
repalloc(void *pointer, Size size)
{
AssertState(MemoryContextEnabled);
AssertArg(MemoryContextIsValid(context));
AssertArg(PointerIsValid(pointer));
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));
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
("size=%d [0x%x]", size, size));
return context->method->realloc(context, pointer, size);
return (*header->context->methods->realloc) (header->context,
pointer, size);
}
/*
* MemoryContextGetName
* Returns pointer to aligned allocated memory in the given context.
*
* Note:
* none
*
* Exceptions:
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
*/
#ifdef NOT_USED
char *
MemoryContextGetName(MemoryContext context)
{
AssertState(MemoryContextEnabled);
AssertArg(MemoryContextIsValid(context));
return context->method->getName(context);
}
#endif
/*
* PointerGetAllocSize
* Returns size of aligned allocated memory given pointer to it.
*
* Note:
* none
*
* Exceptions:
* ???
* BadArgumentsErr if firstTime is true for subsequent calls.
*/
#ifdef NOT_USED
Size
PointerGetAllocSize(Pointer pointer)
{
AssertState(MemoryContextEnabled);
AssertArg(PointerIsValid(pointer));
return PSIZE(pointer);
}
#endif
/*
* MemoryContextSwitchTo
* Returns the current context; installs the given context.
*
* Note:
* none
*
* Exceptions:
* BadState if called when disabled.
* BadArg if context is invalid.
*/
MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
MemoryContext old;
AssertState(MemoryContextEnabled);
AssertArg(MemoryContextIsValid(context));
old = CurrentMemoryContext;
@ -342,195 +465,18 @@ MemoryContextSwitchTo(MemoryContext context)
}
/*
* External Functions
* MemoryContextStrdup
* Like strdup(), but allocate from the specified context
*/
/*
* CreateGlobalMemory
* Returns new global memory context.
*
* Note:
* Assumes name is static.
*
* Exceptions:
* BadState if called when disabled.
* BadState if called outside TopMemoryContext (TopGlobalMemory).
* BadArg if name is invalid.
*/
GlobalMemory
CreateGlobalMemory(char *name) /* XXX MemoryContextName */
char *
MemoryContextStrdup(MemoryContext context, const char *string)
{
GlobalMemory context;
MemoryContext savecxt;
char *nstr;
Size len = strlen(string) + 1;
AssertState(MemoryContextEnabled);
nstr = (char *) MemoryContextAlloc(context, len);
savecxt = MemoryContextSwitchTo(TopMemoryContext);
memcpy(nstr, string, len);
context = (GlobalMemory) newNode(sizeof(struct GlobalMemoryData), T_GlobalMemory);
context->method = &GlobalContextMethodsData;
context->name = name; /* assumes name is static */
AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0);
/* link the context */
OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet);
MemoryContextSwitchTo(savecxt);
return context;
}
/*
* GlobalMemoryDestroy
* Destroys given global memory context.
*
* Exceptions:
* BadState if called when disabled.
* BadState if called outside TopMemoryContext (TopGlobalMemory).
* BadArg if context is invalid GlobalMemory.
* BadArg if context is TopMemoryContext (TopGlobalMemory).
*/
void
GlobalMemoryDestroy(GlobalMemory context)
{
AssertState(MemoryContextEnabled);
AssertArg(IsA(context, GlobalMemory));
AssertArg(context != &TopGlobalMemoryData);
AllocSetReset(&context->setData);
/* unlink and delete the context */
OrderedElemPop(&context->elemData);
MemoryContextFree(TopMemoryContext, (Pointer) context);
}
/*****************************************************************************
* PRIVATE *
*****************************************************************************/
/*
* GlobalMemoryAlloc
* Returns pointer to aligned space in the global context.
*
* Exceptions:
* ExhaustedMemory if allocation fails.
*/
static Pointer
GlobalMemoryAlloc(GlobalMemory this, Size size)
{
return AllocSetAlloc(&this->setData, size);
}
/*
* GlobalMemoryFree
* Frees allocated memory in the global context.
*
* Exceptions:
* BadContextErr if current context is not the global context.
* BadArgumentsErr if pointer is invalid.
*/
static void
GlobalMemoryFree(GlobalMemory this,
Pointer pointer)
{
AllocSetFree(&this->setData, pointer);
}
/*
* GlobalMemoryRealloc
* Returns pointer to aligned space in the global context.
*
* Note:
* Memory associated with the pointer is freed before return.
*
* Exceptions:
* BadContextErr if current context is not the global context.
* BadArgumentsErr if pointer is invalid.
* NoMoreMemoryErr if allocation fails.
*/
static Pointer
GlobalMemoryRealloc(GlobalMemory this,
Pointer pointer,
Size size)
{
return AllocSetRealloc(&this->setData, pointer, size);
}
/*
* GlobalMemoryGetName
* Returns name string for context.
*
* Exceptions:
* ???
*/
static char *
GlobalMemoryGetName(GlobalMemory this)
{
return this->name;
}
/*
* GlobalMemoryDump
* Dumps global memory context for debugging.
*
* Exceptions:
* ???
*/
static void
GlobalMemoryDump(GlobalMemory this)
{
GlobalMemory context;
printf("--\n%s:\n", GlobalMemoryGetName(this));
context = (GlobalMemory) OrderedElemGetPredecessor(&this->elemData);
if (PointerIsValid(context))
printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
context = (GlobalMemory) OrderedElemGetSuccessor(&this->elemData);
if (PointerIsValid(context))
printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
AllocSetDump(&this->setData);
}
/*
* DumpGlobalMemories
* Dumps all global memory contexts for debugging.
*
* Exceptions:
* ???
*/
#ifdef NOT_USED
static void
DumpGlobalMemories()
{
GlobalMemory context;
context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
while (PointerIsValid(context))
{
GlobalMemoryDump(context);
context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
}
}
#endif
/*
* GlobalMemoryStats
* Displays stats about memory consumption of all global contexts.
*/
void
GlobalMemoryStats(void)
{
GlobalMemory context;
context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
while (PointerIsValid(context))
{
AllocSetStats(&context->setData, GlobalMemoryGetName(context));
context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
}
return nstr;
}

View File

@ -1,165 +0,0 @@
/*-------------------------------------------------------------------------
*
* oset.c
* Fixed format ordered set definitions.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/oset.c,v 1.17 2000/04/12 17:16:10 momjian Exp $
*
* NOTE
* XXX This is a preliminary implementation which lacks fail-fast
* XXX validity checking of arguments.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/memutils.h"
static Pointer OrderedElemGetBase(OrderedElem elem);
static void OrderedElemPush(OrderedElem elem);
static void OrderedElemPushHead(OrderedElem elem);
/*
* OrderedElemGetBase
* Returns base of enclosing structure.
*/
static Pointer
OrderedElemGetBase(OrderedElem elem)
{
if (elem == (OrderedElem) NULL)
return (Pointer) NULL;
return (Pointer) ((char *) (elem) - (elem)->set->offset);
}
/*
* OrderedSetInit
*/
void
OrderedSetInit(OrderedSet set, Offset offset)
{
set->head = (OrderedElem) &set->dummy;
set->dummy = NULL;
set->tail = (OrderedElem) &set->head;
set->offset = offset;
}
/*
* OrderedSetContains
* True iff ordered set contains given element.
*/
#ifdef NOT_USED
bool
OrderedSetContains(OrderedSet set, OrderedElem elem)
{
return (bool) (elem->set == set && (elem->next || elem->prev));
}
#endif
/*
* OrderedSetGetHead
*/
Pointer
OrderedSetGetHead(OrderedSet set)
{
OrderedElem elem;
elem = set->head;
if (elem->next)
return OrderedElemGetBase(elem);
return NULL;
}
/*
* OrderedSetGetTail
*/
#ifdef NOT_USED
Pointer
OrderedSetGetTail(OrderedSet set)
{
OrderedElem elem;
elem = set->tail;
if (elem->prev)
return OrderedElemGetBase(elem);
return NULL;
}
#endif
/*
* OrderedElemGetPredecessor
*/
Pointer
OrderedElemGetPredecessor(OrderedElem elem)
{
elem = elem->prev;
if (elem->prev)
return OrderedElemGetBase(elem);
return NULL;
}
/*
* OrderedElemGetSuccessor
*/
Pointer
OrderedElemGetSuccessor(OrderedElem elem)
{
elem = elem->next;
if (elem->next)
return OrderedElemGetBase(elem);
return NULL;
}
/*
* OrderedElemPop
*/
void
OrderedElemPop(OrderedElem elem)
{
elem->next->prev = elem->prev;
elem->prev->next = elem->next;
/* assignments used only for error detection */
elem->next = NULL;
elem->prev = NULL;
}
/*
* OrderedElemPushInto
*/
void
OrderedElemPushInto(OrderedElem elem, OrderedSet set)
{
elem->set = set;
/* mark as unattached */
elem->next = NULL;
elem->prev = NULL;
OrderedElemPush(elem);
}
/*
* OrderedElemPush
*/
static void
OrderedElemPush(OrderedElem elem)
{
OrderedElemPushHead(elem);
}
/*
* OrderedElemPushHead
*/
static void
OrderedElemPushHead(OrderedElem elem)
{
elem->next = elem->set->head;
elem->prev = (OrderedElem) &elem->set->head;
elem->next->prev = elem;
elem->prev->next = elem;
}

View File

@ -1,41 +0,0 @@
/*-------------------------------------------------------------------------
*
* palloc.c
* POSTGRES memory allocator code.
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.18 2000/05/30 00:49:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
/* ----------------------------------------------------------------
* User library functions
* ----------------------------------------------------------------
*/
/* ----------
* palloc(), pfree() and repalloc() are now macros in palloc.h
* ----------
*/
char *
pstrdup(const char *string)
{
char *nstr;
int len;
nstr = palloc(len = strlen(string) + 1);
memcpy(nstr, string, len);
return nstr;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.36 2000/04/12 17:16:10 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.37 2000/06/28 03:32:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -40,67 +40,28 @@
*
* struct PortalD {
* char* name;
* classObj(PortalVariableMemory) variable;
* classObj(PortalHeapMemory) heap;
* classObj(MemoryContext) heap;
* List queryDesc;
* EState state;
* void (*cleanup) ARGS((Portal portal));
* };
*
* I hope this makes things clearer to whoever reads this -cim 2/22/91
*
* Here is an old comment taken from nodes/memnodes.h
*
* MemoryContext
* A logical context in which memory allocations occur.
*
* The types of memory contexts can be thought of as members of the
* following inheritance hierarchy with properties summarized below.
*
* Node
* |
* MemoryContext___
* / \
* GlobalMemory PortalMemoryContext
* / \
* PortalVariableMemory PortalHeapMemory
*
* Flushed at Flushed at Checkpoints
* Transaction Portal
* Commit Close
*
* GlobalMemory n n n
* PortalVariableMemory n y n
* PortalHeapMemory y y y *
*
*/
#include "postgres.h"
#include "lib/hasht.h"
#include "utils/module.h"
#include "utils/memutils.h"
#include "utils/portal.h"
static void CollectNamedPortals(Portal *portalP, int destroy);
static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
/* ----------------
* ALLOCFREE_ERROR_ABORT
* define this if you want a core dump when you try to
* free memory already freed -cim 2/9/91
* ----------------
*/
#undef ALLOCFREE_ERROR_ABORT
/* ----------------
* Global state
* ----------------
*/
static int PortalManagerEnableCount = 0;
#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
typedef struct portalhashent
@ -109,8 +70,6 @@ typedef struct portalhashent
Portal portal;
} PortalHashEnt;
#define PortalManagerEnabled (PortalManagerEnableCount >= 1)
static HTAB *PortalHashTable = NULL;
#define PortalHashTableLookup(NAME, PORTAL) \
@ -158,263 +117,13 @@ do { \
elog(NOTICE, "trying to delete portal name that does not exist."); \
} while(0)
static GlobalMemory PortalMemory = NULL;
static char PortalMemoryName[] = "Portal";
static Portal BlankPortal = NULL;
/* ----------------
* Internal class definitions
* ----------------
*/
typedef struct HeapMemoryBlockData
{
AllocSetData setData;
FixedItemData itemData;
} HeapMemoryBlockData;
typedef HeapMemoryBlockData *HeapMemoryBlock;
#define HEAPMEMBLOCK(context) \
((HeapMemoryBlock)(context)->block)
/* ----------------------------------------------------------------
* Variable and heap memory methods
* ----------------------------------------------------------------
*/
/* ----------------
* PortalVariableMemoryAlloc
* ----------------
*/
static Pointer
PortalVariableMemoryAlloc(PortalVariableMemory this,
Size size)
{
return AllocSetAlloc(&this->setData, size);
}
/* ----------------
* PortalVariableMemoryFree
* ----------------
*/
static void
PortalVariableMemoryFree(PortalVariableMemory this,
Pointer pointer)
{
AllocSetFree(&this->setData, pointer);
}
/* ----------------
* PortalVariableMemoryRealloc
* ----------------
*/
static Pointer
PortalVariableMemoryRealloc(PortalVariableMemory this,
Pointer pointer,
Size size)
{
return AllocSetRealloc(&this->setData, pointer, size);
}
/* ----------------
* PortalVariableMemoryGetName
* ----------------
*/
static char *
PortalVariableMemoryGetName(PortalVariableMemory this)
{
return vararg_format("%s-var", PortalVariableMemoryGetPortal(this)->name);
}
/* ----------------
* PortalVariableMemoryDump
* ----------------
*/
static void
PortalVariableMemoryDump(PortalVariableMemory this)
{
printf("--\n%s:\n", PortalVariableMemoryGetName(this));
AllocSetDump(&this->setData); /* XXX is this the right interface */
}
/* ----------------
* PortalHeapMemoryAlloc
* ----------------
*/
static Pointer
PortalHeapMemoryAlloc(PortalHeapMemory this,
Size size)
{
HeapMemoryBlock block = HEAPMEMBLOCK(this);
AssertState(PointerIsValid(block));
return AllocSetAlloc(&block->setData, size);
}
/* ----------------
* PortalHeapMemoryFree
* ----------------
*/
static void
PortalHeapMemoryFree(PortalHeapMemory this,
Pointer pointer)
{
HeapMemoryBlock block = HEAPMEMBLOCK(this);
AssertState(PointerIsValid(block));
if (AllocSetContains(&block->setData, pointer))
AllocSetFree(&block->setData, pointer);
else
{
elog(NOTICE,
"PortalHeapMemoryFree: 0x%p not in alloc set!",
pointer);
#ifdef ALLOCFREE_ERROR_ABORT
Assert(AllocSetContains(&block->setData, pointer));
#endif /* ALLOCFREE_ERROR_ABORT */
}
}
/* ----------------
* PortalHeapMemoryRealloc
* ----------------
*/
static Pointer
PortalHeapMemoryRealloc(PortalHeapMemory this,
Pointer pointer,
Size size)
{
HeapMemoryBlock block = HEAPMEMBLOCK(this);
AssertState(PointerIsValid(block));
return AllocSetRealloc(&block->setData, pointer, size);
}
/* ----------------
* PortalHeapMemoryGetName
* ----------------
*/
static char *
PortalHeapMemoryGetName(PortalHeapMemory this)
{
return vararg_format("%s-heap", PortalHeapMemoryGetPortal(this)->name);
}
/* ----------------
* PortalHeapMemoryDump
* ----------------
*/
static void
PortalHeapMemoryDump(PortalHeapMemory this)
{
HeapMemoryBlock block;
printf("--\n%s:\n", PortalHeapMemoryGetName(this));
/* XXX is this the right interface */
if (PointerIsValid(this->block))
AllocSetDump(&HEAPMEMBLOCK(this)->setData);
/* dump the stack too */
for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
PointerIsValid(block);
block = (HeapMemoryBlock)
FixedStackGetNext(&this->stackData, (Pointer) block))
{
printf("--\n");
AllocSetDump(&block->setData);
}
}
/* ----------------------------------------------------------------
* variable / heap context method tables
* ----------------------------------------------------------------
*/
static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
PortalVariableMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
PortalVariableMemoryFree, /* void (*)(this, Pointer) pfree */
PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer) repalloc */
PortalVariableMemoryGetName,/* char* (*)(this) getName */
PortalVariableMemoryDump /* void (*)(this) dump */
};
static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
PortalHeapMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
PortalHeapMemoryFree, /* void (*)(this, Pointer) pfree */
PortalHeapMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
PortalHeapMemoryGetName, /* char* (*)(this) getName */
PortalHeapMemoryDump /* void (*)(this) dump */
};
static MemoryContext PortalMemory = NULL;
/* ----------------------------------------------------------------
* private internal support routines
* ----------------------------------------------------------------
*/
/* ----------------
* CreateNewBlankPortal
* ----------------
*/
static void
CreateNewBlankPortal()
{
Portal portal;
AssertState(!PortalIsValid(BlankPortal));
/*
* make new portal structure
*/
portal = (Portal)
MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
/*
* initialize portal variable context
*/
NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
portal->variable.method = &PortalVariableContextMethodsData;
/*
* initialize portal heap context
*/
NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
portal->heap.block = NULL;
FixedStackInit(&portal->heap.stackData,
offsetof(HeapMemoryBlockData, itemData));
portal->heap.method = &PortalHeapContextMethodsData;
/*
* set bogus portal name
*/
portal->name = "** Blank Portal **";
/* initialize portal query */
portal->queryDesc = NULL;
portal->attinfo = NULL;
portal->state = NULL;
portal->cleanup = NULL;
/*
* install blank portal
*/
BlankPortal = portal;
}
bool
PortalNameIsSpecial(char *pname)
{
if (strcmp(pname, VACPNAME) == 0)
return true;
if (strcmp(pname, TRUNCPNAME) == 0)
return true;
return false;
}
/*
* This routine is used to collect all portals created in this xaction
@ -447,12 +156,6 @@ CollectNamedPortals(Portal *portalP, int destroy)
Assert(portalP);
Assert(*portalP);
/*
* Don't delete special portals, up to portal creator to do this
*/
if (PortalNameIsSpecial((*portalP)->name))
return;
portalList[listIndex] = *portalP;
listIndex++;
if (listIndex == maxIndex)
@ -472,179 +175,50 @@ AtEOXact_portals()
CollectNamedPortals(NULL, 1);
}
/* ----------------
* PortalDump
* ----------------
*/
#ifdef NOT_USED
static void
PortalDump(Portal *thisP, int dummy)
{
/* XXX state/argument checking here */
PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
}
#endif
/* ----------------
* DumpPortals
* ----------------
*/
#ifdef NOT_USED
static void
DumpPortals()
{
/* XXX state checking here */
HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0);
}
#endif
/* ----------------------------------------------------------------
* public portal interface functions
* ----------------------------------------------------------------
*/
/*
* EnablePortalManager
* Enables/disables the portal management module.
* Enables the portal management module at backend startup.
*/
void
EnablePortalManager(bool on)
EnablePortalManager(void)
{
static bool processing = false;
HASHCTL ctl;
AssertState(!processing);
AssertArg(BoolIsValid(on));
Assert(PortalMemory == NULL);
if (BypassEnable(&PortalManagerEnableCount, on))
return;
PortalMemory = AllocSetContextCreate(TopMemoryContext,
"PortalMemory",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
processing = true;
ctl.keysize = MAX_PORTALNAME_LEN;
ctl.datasize = sizeof(Portal);
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 = NULL;
EnableMemoryContext(true);
}
processing = false;
/*
* use PORTALS_PER_USER, defined in utils/portal.h as a guess of
* how many hash table entries to create, initially
*/
PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
}
/*
* GetPortalByName
* Returns a portal given a portal name; returns blank portal given
* NULL; returns invalid portal if portal not found.
*
* Exceptions:
* BadState if called when disabled.
* Returns a portal given a portal name, or NULL if name not found.
*/
Portal
GetPortalByName(char *name)
{
Portal portal;
AssertState(PortalManagerEnabled);
if (PointerIsValid(name))
PortalHashTableLookup(name, portal);
else
{
if (!PortalIsValid(BlankPortal))
CreateNewBlankPortal();
portal = BlankPortal;
}
return portal;
}
/*
* BlankPortalAssignName
* Returns former blank portal as portal with given name.
*
* Side effect:
* All references to the former blank portal become incorrect.
*
* Exceptions:
* BadState if called when disabled.
* BadState if called without an intervening call to GetPortalByName(NULL).
* BadArg if portal name is invalid.
* "WARN" if portal name is in use.
*/
Portal
BlankPortalAssignName(char *name) /* XXX PortalName */
{
Portal portal;
uint16 length;
AssertState(PortalManagerEnabled);
AssertState(PortalIsValid(BlankPortal));
AssertArg(PointerIsValid(name)); /* XXX PortalName */
portal = GetPortalByName(name);
if (PortalIsValid(portal))
{
elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
return portal;
}
/*
* remove blank portal
*/
portal = BlankPortal;
BlankPortal = NULL;
/*
* initialize portal name
*/
length = 1 + strlen(name);
portal->name = (char *)
MemoryContextAlloc((MemoryContext) &portal->variable, length);
strncpy(portal->name, name, length);
/*
* put portal in table
*/
PortalHashTableInsert(portal);
portal = NULL;
return portal;
}
@ -666,7 +240,6 @@ PortalSetQuery(Portal portal,
EState *state,
void (*cleanup) (Portal portal))
{
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
AssertArg(IsA((Node *) state, EState));
@ -687,7 +260,6 @@ PortalSetQuery(Portal portal,
QueryDesc *
PortalGetQueryDesc(Portal portal)
{
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
return portal->queryDesc;
@ -704,7 +276,6 @@ PortalGetQueryDesc(Portal portal)
EState *
PortalGetState(Portal portal)
{
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
return portal->state;
@ -714,63 +285,48 @@ PortalGetState(Portal portal)
* CreatePortal
* Returns a new portal given a name.
*
* Note:
* This is expected to be of very limited usability. See instead,
* BlankPortalAssignName.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if portal name is invalid.
* "WARN" if portal name is in use.
* "NOTICE" if portal name is in use (existing portal is returned!)
*/
Portal
CreatePortal(char *name) /* XXX PortalName */
CreatePortal(char *name)
{
Portal portal;
uint16 length;
AssertState(PortalManagerEnabled);
AssertArg(PointerIsValid(name)); /* XXX PortalName */
AssertArg(PointerIsValid(name));
portal = GetPortalByName(name);
if (PortalIsValid(portal))
{
elog(NOTICE, "CreatePortal: portal %s already exists", name);
elog(NOTICE, "CreatePortal: portal \"%s\" already exists", name);
return portal;
}
/* make new portal structure */
portal = (Portal)
MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
/* 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;
portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
/* initialize portal name */
length = 1 + strlen(name);
portal->name = (char *)
MemoryContextAlloc((MemoryContext) &portal->variable, length);
strncpy(portal->name, name, length);
portal->name = MemoryContextStrdup(PortalMemory, name);
/* initialize portal heap context */
portal->heap = AllocSetContextCreate(PortalMemory,
"PortalHeapMemory",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* initialize portal query */
portal->queryDesc = NULL;
portal->attinfo = NULL;
portal->state = NULL;
portal->cleanup = NULL;
/* put portal in table */
PortalHashTableInsert(portal);
/* Trap(PointerIsValid(name), Unimplemented); */
return portal;
}
@ -787,240 +343,29 @@ PortalDrop(Portal *portalP)
{
Portal portal = *portalP;
AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
/* remove portal from table if not blank portal */
if (portal != BlankPortal)
PortalHashTableDelete(portal);
/* remove portal from hash table */
PortalHashTableDelete(portal);
/* reset portal */
if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal);
PortalResetHeapMemory(portal);
MemoryContextFree((MemoryContext) &portal->variable,
(Pointer) portal->name);
AllocSetReset(&portal->variable.setData); /* XXX log */
/* release subsidiary storage */
MemoryContextDelete(PortalGetHeapMemory(portal));
/*
* 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);
AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
context = (PortalHeapMemory) CurrentMemoryContext;
AssertState(PointerIsValid(context->block)); /* XXX Trap(...) */
/* free current mode */
AllocSetReset(&HEAPMEMBLOCK(context)->setData);
MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
context->block);
/* restore previous mode */
context->block = FixedStackPop(&context->stackData);
}
/*
* PortalGetVariableMemory
* Returns variable memory context for a given portal.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if portal is invalid.
*/
PortalVariableMemory
PortalGetVariableMemory(Portal portal)
{
return &portal->variable;
/* release name and portal data (both are in PortalMemory) */
pfree(portal->name);
pfree(portal);
}
/*
* PortalGetHeapMemory
* Returns heap memory context for a given portal.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if portal is invalid.
*/
PortalHeapMemory
MemoryContext
PortalGetHeapMemory(Portal portal)
{
return &portal->heap;
}
/*
* PortalVariableMemoryGetPortal
* Returns portal containing given variable memory context.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if context is invalid.
*/
static Portal
PortalVariableMemoryGetPortal(PortalVariableMemory context)
{
return (Portal) ((char *) context - offsetof(PortalD, variable));
}
/*
* PortalHeapMemoryGetPortal
* Returns portal containing given heap memory context.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if context is invalid.
*/
static Portal
PortalHeapMemoryGetPortal(PortalHeapMemory context)
{
return (Portal) ((char *) context - offsetof(PortalD, heap));
}
/*
* PortalVariableMemoryGetHeapMemory
* Returns heap memory context associated with given variable memory.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if context is invalid.
*/
#ifdef NOT_USED
PortalHeapMemory
PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
{
return ((PortalHeapMemory) ((char *) context
- offsetof(PortalD, variable)
+offsetof(PortalD, heap)));
}
#endif
/*
* PortalHeapMemoryGetVariableMemory
* Returns variable memory context associated with given heap memory.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if context is invalid.
*/
static PortalVariableMemory
PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
{
return ((PortalVariableMemory) ((char *) context
- offsetof(PortalD, heap)
+offsetof(PortalD, variable)));
return portal->heap;
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: command.h,v 1.18 2000/04/12 17:16:31 momjian Exp $
* $Id: command.h,v 1.19 2000/06/28 03:32:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,7 +16,6 @@
#include "utils/portal.h"
extern MemoryContext PortalExecutorHeapMemory;
/*
* PerformPortalFetch

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: hashjoin.h,v 1.16 2000/01/26 05:58:05 momjian Exp $
* $Id: hashjoin.h,v 1.17 2000/06/28 03:33:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -22,20 +22,19 @@
*
* Each active hashjoin has a HashJoinTable control block which is
* palloc'd in the executor's context. All other storage needed for
* the hashjoin is kept in a private "named portal", one for each hashjoin.
* the hashjoin is kept in private memory contexts, two for each hashjoin.
* This makes it easy and fast to release the storage when we don't need it
* anymore.
*
* The portal manager guarantees that portals will be discarded at end of
* transaction, so we have no problem with a memory leak if the join is
* The contexts are made children of TransactionCommandContext, ensuring
* that they will be discarded at end of statement even if the join is
* aborted early by an error. (Likewise, any temporary files we make will
* be cleaned up by the virtual file manager in event of an error.)
*
* Storage that should live through the entire join is allocated from the
* portal's "variable context", while storage that is only wanted for the
* current batch is allocated in the portal's "heap context". By popping
* the portal's heap at the end of a batch, we free all the per-batch storage
* reliably and without tedium.
* "hashCxt", while storage that is only wanted for the current batch is
* allocated in the "batchCxt". By resetting the batchCxt at the end of
* each batch, we free all the per-batch storage reliably and without tedium.
* ----------------------------------------------------------------
*/
@ -80,15 +79,6 @@ typedef struct HashTableData
* to hash buckets and output.
*/
/*
* Ugly kluge: myPortal ought to be declared as type Portal (ie,
* PortalD*) but if we try to include utils/portal.h here, we end up
* with a circular dependency of include files! Until the various
* node.h files are restructured in a cleaner way, we have to fake it.
* The most reliable fake seems to be to declare myPortal as void *
* and then cast it to the right things in nodeHash.c.
*/
void *myPortal; /* where to keep working storage */
MemoryContext hashCxt; /* context for whole-hash-join storage */
MemoryContext batchCxt; /* context for this-batch-only storage */
} HashTableData;

View File

@ -28,7 +28,6 @@
#include "utils/fcache.h"
#include "utils/datum.h"
#include "utils/syscache.h"
#include "utils/portal.h"
#include "utils/builtins.h"
#include "catalog/pg_language.h"
#include "access/heapam.h"
@ -95,4 +94,6 @@ extern void *SPI_repalloc(void *pointer, Size size);
extern void SPI_pfree(void *pointer);
extern void SPI_freetuple(HeapTuple pointer);
extern void AtEOXact_SPI(void);
#endif /* SPI_H */

View File

@ -3,7 +3,7 @@
* spi.c
* Server Programming Interface private declarations
*
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.6 1999/07/15 15:21:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.7 2000/06/28 03:33:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,7 +17,8 @@ typedef struct
List *qtlist;
uint32 processed; /* by Executor */
SPITupleTable *tuptable;
Portal portal; /* portal per procedure */
MemoryContext procCxt; /* procedure context */
MemoryContext execCxt; /* executor context */
MemoryContext savedcxt;
CommandId savedId;
} _SPI_connection;

View File

@ -1,115 +0,0 @@
/*-------------------------------------------------------------------------
*
* fstack.h
* Fixed format stack definitions.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: fstack.h,v 1.9 2000/01/26 05:58:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Note:
* Fixed format stacks assist in the construction of FIFO stacks of
* fixed format structures. Structures which are to be stackable
* should contain a FixedItemData component. A stack is initilized
* with the offset of the FixedItemData component of the structure
* it will hold. By doing so, push and pop operations are simplified
* for the callers. All references to stackable items are pointers
* to the base of the structure instead of pointers to the
* FixedItemData component.
*
*/
#ifndef FSTACK_H
#define FSTACK_H
/*
* FixedItem
* Fixed format stackable item chain component.
*
* Note:
* Structures must contain one FixedItemData component per stack in
* which it will be an item.
*/
typedef struct FixedItemData FixedItemData;
typedef FixedItemData *FixedItem;
struct FixedItemData
{
FixedItem next; /* next item or NULL */
};
/*
* FixedStack
* Fixed format stack.
*/
typedef struct FixedStackData
{
FixedItem top; /* Top item on the stack or NULL */
Offset offset; /* Offset from struct base to item */
/* this could be signed short int! */
} FixedStackData;
typedef FixedStackData *FixedStack;
/*
* FixedStackInit
* Iniitializes stack for structures with given fixed component offset.
*
* Exceptions:
* BadArg if stack is invalid pointer.
*/
extern void FixedStackInit(FixedStack stack, Offset offset);
/*
* FixedStackPop
* Returns pointer to top structure on stack or NULL if empty stack.
*
* Exceptions:
* BadArg if stack is invalid.
*/
Pointer FixedStackPop(FixedStack stack);
/*
* FixedStackPush
* Places structure associated with pointer onto top of stack.
*
* Exceptions:
* BadArg if stack is invalid.
* BadArg if pointer is invalid.
*/
extern void FixedStackPush(FixedStack stack, Pointer pointer);
/*
* FixedStackGetTop
* Returns pointer to top structure of a stack. This item is not poped.
*
* Note:
* This is not part of the normal stack interface. It is intended for
* debugging use only.
*
* Exceptions:
* BadArg if stack is invalid.
*/
extern Pointer FixedStackGetTop(FixedStack stack);
/*
* FixedStackGetNext
* Returns pointer to next structure after pointer of a stack.
*
* Note:
* This is not part of the normal stack interface. It is intended for
* debugging use only.
*
* Exceptions:
* BadArg if stack is invalid.
* BadArg if pointer is invalid.
* BadArg if stack does not contain pointer.
*/
extern Pointer FixedStackGetNext(FixedStack stack, Pointer pointer);
#endif /* FSTACK_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pqsignal.h,v 1.13 2000/06/15 00:52:11 momjian Exp $
* $Id: pqsignal.h,v 1.14 2000/06/28 03:33:14 tgl Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
@ -24,28 +24,18 @@
extern sigset_t UnBlockSig,
BlockSig;
#define PG_INITMASK() ( \
sigemptyset(&UnBlockSig), \
sigfillset(&BlockSig) \
)
#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)
#else
extern int UnBlockSig,
BlockSig;
#define PG_INITMASK() ( \
UnBlockSig = 0, \
BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) | \
sigmask(SIGTERM) | sigmask(SIGALRM) | \
sigmask(SIGINT) | sigmask(SIGUSR1) | \
sigmask(SIGUSR2) | sigmask(SIGCHLD) | \
sigmask(SIGWINCH) | sigmask(SIGFPE) \
)
#define PG_SETMASK(mask) sigsetmask(*((int*)(mask)))
#endif
typedef void (*pqsigfunc) (int);
extern void pqinitmask(void);
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
#endif /* PQSIGNAL_H */

View File

@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: miscadmin.h,v 1.60 2000/06/15 00:52:04 momjian Exp $
* $Id: miscadmin.h,v 1.61 2000/06/28 03:32:56 tgl Exp $
*
* NOTES
* some of the information in this file will be moved to
@ -105,8 +105,6 @@ extern bool enableFsync;
extern bool allowSystemTableMods;
extern int SortMem;
extern Oid LastOidProcessed; /* for query rewrite */
/* a few postmaster startup options are exported here so the
configuration file processor has access to them */
@ -189,9 +187,10 @@ typedef int16 ExitStatus;
/* in utils/init/postinit.c */
extern bool PostgresIsInitialized;
extern int lockingOff;
extern void InitPostgres(const char *dbname);
extern void BaseInit(void);
/* one of the ways to get out of here */
#define ExitPostgres(status) proc_exec(status)

View File

@ -7,100 +7,88 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: memnodes.h,v 1.16 2000/01/26 05:58:16 momjian Exp $
* $Id: memnodes.h,v 1.17 2000/06/28 03:33:15 tgl Exp $
*
* XXX the typedefs in this file are different from the other ???nodes.h;
* they are pointers to structures instead of the structures themselves.
* If you're wondering, this is plain laziness. I don't want to touch
* the memory context code which should be revamped altogether some day.
* - ay 10/94
*-------------------------------------------------------------------------
*/
#ifndef MEMNODES_H
#define MEMNODES_H
#include "lib/fstack.h"
#include "nodes/nodes.h"
#include "utils/memutils.h"
/*
* MemoryContext
* A logical context in which memory allocations occur.
*
* The types of memory contexts can be thought of as members of the
* following inheritance hierarchy with properties summarized below.
* MemoryContext itself is an abstract type that can have multiple
* implementations, though for now we have only AllocSetContext.
* The function pointers in MemoryContextMethods define one specific
* implementation of MemoryContext --- they are a virtual function table
* in C++ terms.
*
* Node
* |
* MemoryContext___
* / \
* GlobalMemory PortalMemoryContext
* / \
* PortalVariableMemory PortalHeapMemory
* Node types that are actual implementations of memory contexts must
* begin with the same fields as MemoryContext.
*
* Flushed at Flushed at Checkpoints
* Transaction Portal
* Commit Close
*
* GlobalMemory n n n
* PortalVariableMemory n y n
* PortalHeapMemory y y y
* Note: for largely historical reasons, typedef MemoryContext is a pointer
* to the context struct rather than the struct type itself.
*/
typedef struct MemoryContextMethodsData
typedef struct MemoryContextMethods
{
Pointer (*alloc) ();
void (*free_p) (); /* need to use free as a #define, so can't
* use free */
Pointer (*realloc) ();
char *(*getName) ();
void (*dump) ();
} *MemoryContextMethods;
void *(*alloc) (MemoryContext context, Size size);
/* call this free_p in case someone #define's free() */
void (*free_p) (MemoryContext context, void *pointer);
void *(*realloc) (MemoryContext context, void *pointer, Size size);
void (*init) (MemoryContext context);
void (*reset) (MemoryContext context);
void (*delete) (MemoryContext context);
void (*stats) (MemoryContext context);
} MemoryContextMethods;
typedef struct MemoryContextData
{
NodeTag type;
MemoryContextMethods method;
NodeTag type; /* identifies exact kind of context */
MemoryContextMethods *methods; /* virtual function table */
MemoryContext parent; /* NULL if no parent (toplevel context) */
MemoryContext firstchild; /* head of linked list of children */
MemoryContext nextchild; /* next child of same parent */
char *name; /* context name (just for debugging) */
} MemoryContextData;
/* utils/mcxt.h contains typedef struct MemoryContextData *MemoryContext */
/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */
/* think about doing this right some time but we'll have explicit fields
for now -ay 10/94 */
typedef struct GlobalMemoryData
/*
* AllocSetContext is our standard implementation of MemoryContext.
*/
typedef struct AllocBlockData *AllocBlock; /* internal to aset.c */
typedef struct AllocChunkData *AllocChunk;
typedef struct AllocSetContext
{
NodeTag type;
MemoryContextMethods method;
AllocSetData setData;
char *name;
OrderedElemData elemData;
} GlobalMemoryData;
MemoryContextData header; /* Standard memory-context fields */
/* Info about storage allocated in this context: */
AllocBlock blocks; /* head of list of blocks in this set */
#define ALLOCSET_NUM_FREELISTS 8
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
/* Allocation parameters for this context: */
Size initBlockSize; /* initial block size */
Size maxBlockSize; /* maximum block size */
AllocBlock keeper; /* if not NULL, keep this block
* over resets */
} AllocSetContext;
/* utils/mcxt.h contains typedef struct GlobalMemoryData *GlobalMemory */
typedef struct MemoryContextData *PortalMemoryContext;
typedef struct PortalVariableMemoryData
{
NodeTag type;
MemoryContextMethods method;
AllocSetData setData;
} *PortalVariableMemory;
typedef struct PortalHeapMemoryData
{
NodeTag type;
MemoryContextMethods method;
Pointer block;
FixedStackData stackData;
} *PortalHeapMemory;
/*
* MemoryContextIsValid
* True iff memory context is valid.
*
* Add new context types to the set accepted by this macro.
*/
#define MemoryContextIsValid(context) \
(IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \
IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory))
((context) != NULL && \
(IsA((context), AllocSetContext)))
#endif /* MEMNODES_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.69 2000/06/18 22:44:31 tgl Exp $
* $Id: nodes.h,v 1.70 2000/06/28 03:33:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -122,10 +122,7 @@ typedef enum NodeTag
*---------------------
*/
T_MemoryContext = 400,
T_GlobalMemory,
T_PortalMemoryContext,
T_PortalVariableMemory,
T_PortalHeapMemory,
T_AllocSetContext,
/*---------------------
* TAGS FOR VALUE NODES (pg_list.h)

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: geqo.h,v 1.19 2000/05/31 00:28:38 petere Exp $
* $Id: geqo.h,v 1.20 2000/06/28 03:33:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -65,7 +65,6 @@ extern int Geqo_random_seed; /* or negative to use current time */
extern RelOptInfo *geqo(Query *root);
/* routines in geqo_eval.c */
extern void geqo_eval_startup(void);
extern Cost geqo_eval(Query *root, Gene *tour, int num_gene);
extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count,
int num_gene, RelOptInfo *old_rel);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1995, Regents of the University of California
*
* $Id: postgres.h,v 1.41 2000/06/13 07:35:24 tgl Exp $
* $Id: postgres.h,v 1.42 2000/06/28 03:32:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -39,7 +39,6 @@
#include "postgres_ext.h"
#include "c.h"
#include "utils/elog.h"
#include "utils/mcxt.h"
#include "utils/palloc.h"
/* ----------------------------------------------------------------

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: shmem.h,v 1.22 2000/01/26 05:58:33 momjian Exp $
* $Id: shmem.h,v 1.23 2000/06/28 03:33:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -63,14 +63,13 @@ typedef struct SHM_QUEUE
extern void ShmemIndexReset(void);
extern void ShmemCreate(unsigned int key, unsigned int size);
extern int InitShmem(unsigned int key, unsigned int size);
extern long *ShmemAlloc(unsigned long size);
extern void *ShmemAlloc(Size size);
extern int ShmemIsValid(unsigned long addr);
extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
HASHCTL *infoP, int hash_flags);
extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
extern SHMEM_OFFSET ShmemPIDDestroy(int pid);
extern long *ShmemInitStruct(char *name, unsigned long size,
bool *foundPtr);
extern void *ShmemInitStruct(char *name, Size size, bool *foundPtr);
typedef int TableID;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pquery.h,v 1.14 2000/01/26 05:58:35 momjian Exp $
* $Id: pquery.h,v 1.15 2000/06/28 03:33:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -15,20 +15,13 @@
#define PQUERY_H
#include "executor/execdesc.h"
#include "utils/portal.h"
/* moved to execdesc.h
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
CommandDest dest);
*/
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
extern EState *CreateExecutorState(void);
extern Portal PreparePortal(char *portalName);
extern void ProcessPortal(char *portalName, Query *parseTree,
Plan *plan, EState *state, TupleDesc attinfo,
CommandDest dest);
extern void
ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
#endif /* pqueryIncluded */
#endif /* PQUERY_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: tcopprot.h,v 1.30 2000/06/15 03:33:04 momjian Exp $
* $Id: tcopprot.h,v 1.31 2000/06/28 03:33:28 tgl Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
@ -33,12 +33,11 @@ extern bool ShowPortNumber;
#ifndef BOOTSTRAP_INCLUDE
extern List *pg_parse_and_rewrite(char *query_string,
Oid *typev, int nargs,
bool aclOverride);
Oid *typev, int nargs);
extern Plan *pg_plan_query(Query *querytree);
extern void pg_exec_query_dest(char *query_string,
CommandDest dest,
bool aclOverride);
CommandDest dest,
MemoryContext parse_context);
#endif /* BOOTSTRAP_INCLUDE */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catcache.h,v 1.24 2000/06/17 04:56:29 tgl Exp $
* $Id: catcache.h,v 1.25 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -75,8 +75,10 @@ typedef struct catcache
#define InvalidCatalogCacheId (-1)
extern GlobalMemory CacheCxt;
/* this extern duplicates utils/memutils.h... */
extern MemoryContext CacheMemoryContext;
extern void CreateCacheMemoryContext(void);
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
ItemPointer pointer);
extern void ResetSystemCache(void);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: hsearch.h,v 1.15 2000/04/12 17:16:55 momjian Exp $
* $Id: hsearch.h,v 1.16 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -84,8 +84,7 @@ typedef struct htab
char *segbase; /* segment base address for calculating
* pointer values */
SEG_OFFSET *dir; /* 'directory' of segm starts */
long *(*alloc) (); /* memory allocator (long * for alignment
* reasons) */
void *(*alloc) (Size); /* memory allocator */
} HTAB;
typedef struct hashctl
@ -99,7 +98,7 @@ typedef struct hashctl
long max_dsize; /* limit to dsize if directory size is
* limited */
long *segbase; /* base for calculating bucket + seg ptrs */
long *(*alloc) (); /* memory allocation function */
void *(*alloc) (Size); /* memory allocation function */
long *dir; /* directory if allocated already */
long *hctl; /* location of header information in shd
* mem */

View File

@ -1,60 +0,0 @@
/*-------------------------------------------------------------------------
*
* mcxt.h
* POSTGRES memory context definitions.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: mcxt.h,v 1.17 2000/05/21 02:23:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef MCXT_H
#define MCXT_H
/* These types are declared in nodes/memnodes.h, but most users of memory
* allocation should just treat them as abstract types, so we do not provide
* the struct contents here.
*/
typedef struct MemoryContextData *MemoryContext;
typedef struct GlobalMemoryData *GlobalMemory;
extern DLLIMPORT MemoryContext CurrentMemoryContext;
extern MemoryContext TopMemoryContext;
/*
* MaxAllocSize
* Arbitrary limit on size of allocations.
*
* Note:
* There is no guarantee that allocations smaller than MaxAllocSize
* will succeed. Allocation requests larger than MaxAllocSize will
* be summarily denied.
*
* This value should not be referenced except in one place in the code.
*
* XXX This should be defined in a file of tunable constants.
*/
#define MaxAllocSize (0xfffffff) /* 16G - 1 */
/*
* prototypes for functions in mcxt.c
*/
extern void EnableMemoryContext(bool on);
extern Pointer MemoryContextAlloc(MemoryContext context, Size size);
extern Pointer MemoryContextRealloc(MemoryContext context,
Pointer pointer,
Size size);
extern void MemoryContextFree(MemoryContext context, Pointer pointer);
extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
extern GlobalMemory CreateGlobalMemory(char *name);
extern void GlobalMemoryDestroy(GlobalMemory context);
extern void GlobalMemoryStats(void);
#endif /* MCXT_H */

View File

@ -1,230 +1,114 @@
/*-------------------------------------------------------------------------
*
* memutils.h
* this file contains general memory alignment, allocation
* and manipulation stuff that used to be spread out
* between the following files:
*
* align.h alignment macros
* aset.h memory allocation set stuff
* oset.h (used by aset.h)
* This file contains declarations for memory allocation utility
* functions. These are functions that are not quite widely used
* enough to justify going in utils/palloc.h, but are still part
* of the API of the memory management subsystem.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: memutils.h,v 1.35 2000/05/21 02:23:28 tgl Exp $
* $Id: memutils.h,v 1.36 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef MEMUTILS_H
#define MEMUTILS_H
/* ----------------
* Alignment macros: align a length or address appropriately for a given type.
*
* There used to be some incredibly crufty platform-dependent hackery here,
* but now we rely on the configure script to get the info for us. Much nicer.
*
* NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
* That case seems extremely unlikely to occur in practice, however.
* ----------------
*/
#include "nodes/memnodes.h"
#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN))
#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN))
#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN))
#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
/*****************************************************************************
* oset.h -- Fixed format ordered set definitions. *
*****************************************************************************/
/* Note:
* Fixed format ordered sets are <EXPLAIN>.
* XXX This is a preliminary version. Work is needed to explain
* XXX semantics of the external definitions. Otherwise, the
* XXX functional interface should not change.
*
*/
typedef struct OrderedElemData OrderedElemData;
typedef OrderedElemData *OrderedElem;
typedef struct OrderedSetData OrderedSetData;
typedef OrderedSetData *OrderedSet;
struct OrderedElemData
{
OrderedElem next; /* Next elem or &this->set->dummy */
OrderedElem prev; /* Previous elem or &this->set->head */
OrderedSet set; /* Parent set */
};
struct OrderedSetData
{
OrderedElem head; /* First elem or &this->dummy */
OrderedElem dummy; /* (hack) Terminator == NULL */
OrderedElem tail; /* Last elem or &this->head */
Offset offset; /* Offset from struct base to elem */
/* this could be signed short int! */
};
extern void OrderedSetInit(OrderedSet set, Offset offset);
extern Pointer OrderedSetGetHead(OrderedSet set);
extern Pointer OrderedElemGetPredecessor(OrderedElem elem);
extern Pointer OrderedElemGetSuccessor(OrderedElem elem);
extern void OrderedElemPop(OrderedElem elem);
extern void OrderedElemPushInto(OrderedElem elem, OrderedSet Set);
/*****************************************************************************
* aset.h -- Allocation set definitions. *
*****************************************************************************/
/*
* Description:
* An allocation set is a set containing allocated elements. When
* an allocation is requested for a set, memory is allocated and a
* pointer is returned. Subsequently, this memory may be freed or
* reallocated. In addition, an allocation set may be reset which
* will cause all memory allocated within it to be freed.
*
* XXX The following material about allocation modes is all OUT OF DATE.
* aset.c currently implements only one allocation strategy,
* DynamicAllocMode, and that's the only one anyone ever requests anyway.
* If we ever did have more strategies, the new ones might or might
* not look like what is described here...
*
* Allocations may occur in four different modes. The mode of
* allocation does not affect the behavior of allocations except in
* terms of performance. The allocation mode is set at the time of
* set initialization. Once the mode is chosen, it cannot be changed
* unless the set is reinitialized.
*
* "Dynamic" mode forces all allocations to occur in a heap. This
* is a good mode to use when small memory segments are allocated
* and freed very frequently. This is a good choice when allocation
* characteristics are unknown. This is the default mode.
*
* "Static" mode attempts to allocate space as efficiently as possible
* without regard to freeing memory. This mode should be chosen only
* when it is known that many allocations will occur but that very
* little of the allocated memory will be explicitly freed.
*
* "Tunable" mode is a hybrid of dynamic and static modes. The
* tunable mode will use static mode allocation except when the
* allocation request exceeds a size limit supplied at the time of set
* initialization. "Big" objects are allocated using dynamic mode.
*
* "Bounded" mode attempts to allocate space efficiently given a limit
* on space consumed by the allocation set. This restriction can be
* considered a "soft" restriction, because memory segments will
* continue to be returned after the limit is exceeded. The limit is
* specified at the time of set initialization like for tunable mode.
* MaxAllocSize
* Arbitrary limit on size of allocations.
*
* Note:
* Allocation sets are not automatically reset on a system reset.
* Higher level code is responsible for cleaning up.
* There is no guarantee that allocations smaller than MaxAllocSize
* will succeed. Allocation requests larger than MaxAllocSize will
* be summarily denied.
*
* There may be other modes in the future.
* XXX This should be defined in a file of tunable constants.
*/
#define MaxAllocSize ((Size) 0xfffffff) /* 16G - 1 */
#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
/*
* AllocPointer
* Aligned pointer which may be a member of an allocation set.
* All chunks allocated by any memory context manager are required to be
* preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
* A currently-allocated chunk must contain a backpointer to its owning
* context as well as the allocated size of the chunk. The backpointer is
* used by pfree() and repalloc() to find the context to call. The allocated
* size is not absolutely essential, but it's expected to be needed by any
* reasonable implementation.
*/
typedef Pointer AllocPointer;
typedef struct StandardChunkHeader
{
MemoryContext context; /* owning context */
Size size; /* size of data space allocated in chunk */
} StandardChunkHeader;
#define STANDARDCHUNKHEADERSIZE MAXALIGN(sizeof(StandardChunkHeader))
/*
* AllocMode
* Mode of allocation for an allocation set.
* Standard top-level memory contexts.
*
* Note:
* See above for a description of the various modes.
* Only TopMemoryContext and ErrorContext are initialized by
* MemoryContextInit() itself.
*/
typedef enum AllocMode
{
DynamicAllocMode, /* always dynamically allocate */
StaticAllocMode, /* always "statically" allocate */
TunableAllocMode, /* allocations are "tuned" */
BoundedAllocMode /* allocations bounded to fixed usage */
} AllocMode;
extern MemoryContext TopMemoryContext;
extern MemoryContext ErrorContext;
extern MemoryContext PostmasterContext;
extern MemoryContext CacheMemoryContext;
extern MemoryContext QueryContext;
extern MemoryContext TopTransactionContext;
extern MemoryContext TransactionCommandContext;
#define DefaultAllocMode DynamicAllocMode
typedef struct AllocSetData *AllocSet;
typedef struct AllocBlockData *AllocBlock;
typedef struct AllocChunkData *AllocChunk;
/*
* AllocSet
* Allocation set.
* Memory-context-type-independent functions in mcxt.c
*/
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;
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);
/*
* 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.
* This routine handles the context-type-independent part of memory
* context creation. It's intended to be called from context-type-
* specific creation routines, and noplace else.
*/
typedef struct AllocBlockData
{
AllocSet aset; /* aset that owns this block */
AllocBlock next; /* next block in aset's blocks list */
char *freeptr; /* start of free space in this block */
char *endptr; /* end of space in this block */
} AllocBlockData;
extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
MemoryContextMethods *methods,
MemoryContext parent,
const char *name);
/*
* AllocChunk
* The prefix of each piece of memory in an AllocBlock
* Memory-context-type-specific functions
*/
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;
/* aset.c */
extern MemoryContext AllocSetContextCreate(MemoryContext parent,
const char *name,
Size minContextSize,
Size initBlockSize,
Size maxBlockSize);
/*
* AllocPointerIsValid
* True iff pointer is valid allocation pointer.
* Recommended default alloc parameters, suitable for "ordinary" contexts
* that might hold quite a lot of data.
*/
#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
/*
* AllocSetIsValid
* True iff set is valid allocation set.
*/
#define AllocSetIsValid(set) PointerIsValid(set)
extern void AllocSetInit(AllocSet set, AllocMode mode, Size limit);
extern void AllocSetReset(AllocSet set);
extern bool AllocSetContains(AllocSet set, AllocPointer pointer);
extern AllocPointer AllocSetAlloc(AllocSet set, Size size);
extern void AllocSetFree(AllocSet set, AllocPointer pointer);
extern AllocPointer AllocSetRealloc(AllocSet set, AllocPointer pointer,
Size size);
extern void AllocSetDump(AllocSet set);
extern void AllocSetStats(AllocSet set, const char *ident);
#define ALLOCSET_DEFAULT_MINSIZE (8 * 1024)
#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024)
#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024)
#endif /* MEMUTILS_H */

View File

@ -1,26 +0,0 @@
/*-------------------------------------------------------------------------
*
* module.h
* this file contains general "module" stuff that used to be
* spread out between the following files:
*
* enbl.h module enable stuff
* trace.h module trace stuff (now gone)
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: module.h,v 1.6 2000/01/26 05:58:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef MODULE_H
#define MODULE_H
/*
* prototypes for functions in init/enbl.c
*/
extern bool BypassEnable(int *enableCountInOutP, bool on);
#endif /* MODULE_H */

View File

@ -3,36 +3,85 @@
* palloc.h
* POSTGRES memory allocator definitions.
*
* This file contains the basic memory allocation interface that is
* needed by almost every backend module. It is included directly by
* postgres.h, so the definitions here are automatically available
* everywhere. Keep it lean!
*
* Memory allocation occurs within "contexts". Every chunk obtained from
* palloc()/MemoryContextAlloc() is allocated within a specific context.
* The entire contents of a context can be freed easily and quickly by
* resetting or deleting the context --- this is both faster and less
* prone to memory-leakage bugs than releasing chunks individually.
* We organize contexts into context trees to allow fine-grain control
* over chunk lifetime while preserving the certainty that we will free
* everything that should be freed. See utils/mmgr/README for more info.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: palloc.h,v 1.12 2000/01/26 05:58:38 momjian Exp $
* $Id: palloc.h,v 1.13 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PALLOC_H
#define PALLOC_H
#ifdef PALLOC_IS_MALLOC
#define palloc(s) malloc(s)
#define pfree(p) free(p)
#define repalloc(p,s) realloc((p),(s))
#else /* ! PALLOC_IS_MALLOC */
/* ----------
* In the case we use memory contexts, use macro's for palloc() etc.
* ----------
/*
* 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.
*/
#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)))
typedef struct MemoryContextData *MemoryContext;
#endif /* PALLOC_IS_MALLOC */
/*
* 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))
extern void pfree(void *pointer);
extern void *repalloc(void *pointer, Size size);
extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
/*
* These are like standard strdup() except the copied string is
* allocated in a context, not with malloc().
*/
extern char *MemoryContextStrdup(MemoryContext context, const char *string);
#define pstrdup(str) MemoryContextStrdup(CurrentMemoryContext, (str))
/* ----------------
* Alignment macros: align a length or address appropriately for a given type.
*
* There used to be some incredibly crufty platform-dependent hackery here,
* but now we rely on the configure script to get the info for us. Much nicer.
*
* NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
* That case seems extremely unlikely to occur in practice, however.
* ----------------
*/
#define 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 */

View File

@ -7,16 +7,14 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: portal.h,v 1.23 2000/04/12 17:16:55 momjian Exp $
* $Id: portal.h,v 1.24 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Note:
* A portal is an abstraction which represents the execution state of
* a running query (or a fixed sequence of queries). The "blank portal" is
* a portal with an InvalidName. This blank portal is in existance except
* between calls to BlankPortalAssignName and GetPortalByName(NULL).
* a running query (or a fixed sequence of queries).
*
* Note:
* now that PQ calls can be made from within a backend, a portal
@ -29,27 +27,18 @@
#include "executor/execdesc.h"
#include "nodes/memnodes.h"
typedef struct PortalBlockData
typedef struct PortalD *Portal;
typedef struct PortalD
{
AllocSetData setData;
FixedItemData itemData;
} PortalBlockData;
typedef PortalBlockData *PortalBlock;
typedef struct PortalD PortalD;
typedef PortalD *Portal;
struct PortalD
{
char *name; /* XXX PortalName */
struct PortalVariableMemoryData variable;
struct PortalHeapMemoryData heap;
QueryDesc *queryDesc;
char *name; /* Portal's name */
MemoryContext heap; /* subsidiary memory */
QueryDesc *queryDesc; /* Info about query associated with portal */
TupleDesc attinfo;
EState *state;
void (*cleanup) (Portal);
};
void (*cleanup) (Portal); /* Cleanup routine (optional) */
} PortalD;
/*
* PortalIsValid
@ -57,36 +46,20 @@ struct PortalD
*/
#define PortalIsValid(p) PointerIsValid(p)
/*
* Special portals (well, their names anyway)
*/
#define VACPNAME "<vacuum>"
#define TRUNCPNAME "<truncate>"
extern bool PortalNameIsSpecial(char *pname);
extern void EnablePortalManager(void);
extern void AtEOXact_portals(void);
extern void EnablePortalManager(bool on);
extern Portal CreatePortal(char *name);
extern void PortalDrop(Portal *portalP);
extern Portal GetPortalByName(char *name);
extern Portal BlankPortalAssignName(char *name);
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
TupleDesc attinfo, EState *state,
void (*cleanup) (Portal portal));
extern QueryDesc *PortalGetQueryDesc(Portal portal);
extern EState *PortalGetState(Portal portal);
extern Portal CreatePortal(char *name);
extern void PortalDrop(Portal *portalP);
extern void StartPortalAllocMode(AllocMode mode, Size limit);
extern void EndPortalAllocMode(void);
extern void PortalResetHeapMemory(Portal portal);
extern PortalVariableMemory PortalGetVariableMemory(Portal portal);
extern PortalHeapMemory PortalGetHeapMemory(Portal portal);
extern void CommonSpecialPortalOpen(void);
extern void CommonSpecialPortalClose(void);
extern PortalVariableMemory CommonSpecialPortalGetMemory(void);
extern bool CommonSpecialPortalIsOpen(void);
extern MemoryContext PortalGetHeapMemory(Portal portal);
/* estimate of the maximum number of open portals a user would have,
* used in initially sizing the PortalHashTable in EnablePortalManager()
* used in initially sizing the PortalHashTable in EnablePortalManager()
*/
#define PORTALS_PER_USER 10