Basic Improvements
-
-
Improve freeing of memory when query is already processed
-
-With large join queries the computing time spent for the genetic query
-optimization seems to be a mere fraction of the time
-needs for freeing memory via routine MemoryContextFree,
-file backend/utils/mmgr/mcxt.c.
-Debugging showed that it get stucked in a loop of routine
-OrderedElemPop, file backend/utils/mmgr/oset.c.
-The same problems arise with long queries when using the normal
-
Postgres query optimization algorithm.
-
-
-
Improve genetic algorithm parameter settings
-NOTICE
-BlankPortalAssignName: portal "cursorname" already exists
+NOTICE: Closing pre-existing portal "cursorname"
- This error occurs if cursorname is already declared.
+ This message is reported if the same cursor name was already declared
+ in the current transaction block. The previous definition is
+ discarded.
#
#
# 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 $
#
#-------------------------------------------------------------------------
$(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 \
*
*
* 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
* ----------------
*/
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);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.67 2000/06/18 22:43:51 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.68 2000/06/28 03:31:05 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
*
* These two cases used to be treated identically, but now
* we need to distinguish them. Why? consider the following
- * two situatuons:
+ * two situations:
*
* case 1 case 2
* ------ ------
* 1) user types BEGIN 1) user types BEGIN
* 2) user does something 2) user does something
* 3) user does not like what 3) system aborts for some reason
- * she shes and types ABORT
+ * she sees and types ABORT
*
* In case 1, we want to abort the transaction and return to the
* default state. In case 2, there may be more commands coming
* * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
* * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
*
+ * Low-level transaction abort handling is divided into two phases:
+ * * AbortTransaction() executes as soon as we realize the transaction
+ * has failed. It should release all shared resources (locks etc)
+ * so that we do not delay other backends unnecessarily.
+ * * CleanupTransaction() executes when we finally see a user COMMIT
+ * or ROLLBACK command; it cleans things up and gets us out of
+ * the transaction internally. In particular, we mustn't destroy
+ * TransactionCommandContext until this point.
+ *
* NOTES
* This file is an attempt at a redesign of the upper layer
* of the V1 transaction system which was too poorly thought
* StartTransaction
* CommitTransaction
* AbortTransaction
- * UserAbortTransaction
+ * CleanupTransaction
*
* are provided to do the lower level work like recording
* the transaction status in the log and doing memory cleanup.
#include "commands/async.h"
#include "commands/sequence.h"
#include "commands/trigger.h"
+#include "executor/spi.h"
#include "libpq/be-fsstubs.h"
#include "storage/proc.h"
#include "storage/sinval.h"
-#include "utils/temprel.h"
#include "utils/inval.h"
+#include "utils/memutils.h"
#include "utils/portal.h"
#include "utils/relcache.h"
+#include "utils/temprel.h"
extern bool SharedBufferChanged;
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);
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);
/* --------------------------------
* TranactionFlushEnabled()
- * SetTranactionFlushEnabled()
+ * SetTransactionFlushEnabled()
*
* These are used to test and set the "TransactionFlushState"
* varable. If this variable is true (the default), then
static void
AtStart_Memory()
{
- Portal portal;
- MemoryContext portalContext;
+ /* ----------------
+ * We shouldn't have any transaction contexts already.
+ * ----------------
+ */
+ Assert(TopTransactionContext == NULL);
+ Assert(TransactionCommandContext == NULL);
/* ----------------
- * get the blank portal and its memory context
+ * Create a toplevel context for the transaction.
* ----------------
*/
- portal = GetPortalByName(NULL);
- portalContext = (MemoryContext) PortalGetHeapMemory(portal);
+ TopTransactionContext =
+ AllocSetContextCreate(TopMemoryContext,
+ "TopTransactionContext",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
/* ----------------
- * tell system to allocate in the blank portal context
+ * Create a statement-level context and make it active.
* ----------------
*/
- MemoryContextSwitchTo(portalContext);
- StartPortalAllocMode(DefaultAllocMode, 0);
+ TransactionCommandContext =
+ AllocSetContextCreate(TopTransactionContext,
+ "TransactionCommandContext",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ MemoryContextSwitchTo(TransactionCommandContext);
}
static void
AtCommit_Memory()
{
- Portal portal;
-
/* ----------------
- * Release all heap memory in the blank portal.
+ * Now that we're "out" of a transaction, have the
+ * system allocate things in the top memory context instead
+ * of per-transaction contexts.
* ----------------
*/
- portal = GetPortalByName(NULL);
- PortalResetHeapMemory(portal);
+ MemoryContextSwitchTo(TopMemoryContext);
/* ----------------
- * Now that we're "out" of a transaction, have the
- * system allocate things in the top memory context instead
- * of the blank portal memory context.
+ * Release all transaction-local memory.
* ----------------
*/
- MemoryContextSwitchTo(TopMemoryContext);
+ MemoryContextDelete(TopTransactionContext);
+ TopTransactionContext = NULL;
+ TransactionCommandContext = NULL;
}
/* ----------------------------------------------------------------
static void
AtAbort_Memory()
{
- Portal portal;
+ /* ----------------
+ * Make sure we are in a valid context (not a child of
+ * TransactionCommandContext...)
+ * ----------------
+ */
+ MemoryContextSwitchTo(TransactionCommandContext);
/* ----------------
- * Release all heap memory in the blank portal.
+ * We do not want to destroy transaction contexts yet,
+ * but it should be OK to delete any command-local memory.
* ----------------
*/
- portal = GetPortalByName(NULL);
- PortalResetHeapMemory(portal);
+ MemoryContextResetAndDeleteChildren(TransactionCommandContext);
+}
+
+
+/* ----------------------------------------------------------------
+ * CleanupTransaction stuff
+ * ----------------------------------------------------------------
+ */
+/* --------------------------------
+ * AtCleanup_Memory
+ * --------------------------------
+ */
+static void
+AtCleanup_Memory()
+{
/* ----------------
* Now that we're "out" of a transaction, have the
* system allocate things in the top memory context instead
- * of the blank portal memory context.
+ * of per-transaction contexts.
* ----------------
*/
MemoryContextSwitchTo(TopMemoryContext);
+
+ /* ----------------
+ * Release all transaction-local memory.
+ * ----------------
+ */
+ MemoryContextDelete(TopTransactionContext);
+ TopTransactionContext = NULL;
+ TransactionCommandContext = NULL;
}
+
/* ----------------------------------------------------------------
* interface routines
* ----------------------------------------------------------------
s->state = TRANS_START;
SetReindexProcessing(false);
+
/* ----------------
* generate a new transaction id
* ----------------
* initialize the various transaction subsystems
* ----------------
*/
+ AtStart_Memory();
AtStart_Cache();
AtStart_Locks();
- AtStart_Memory();
/* ----------------
* Tell the trigger manager to we're starting a transaction
}
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 */
-
}
/* --------------------------------
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
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 */
}
/* --------------------------------
/* ----------------
* 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.
* ----------------
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);
}
/* --------------------------------
* 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;
/* ----------------
/* ----------------
* 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;
}
{
/* ----------------
* 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;
/* ----------------
case TBLOCK_BEGIN:
s->blockState = TBLOCK_ABORT;
AbortTransaction();
+ /* CleanupTransaction happens when we exit TBLOCK_ABORT */
break;
/* ----------------
case TBLOCK_INPROGRESS:
s->blockState = TBLOCK_ABORT;
AbortTransaction();
+ /* CleanupTransaction happens when we exit TBLOCK_ABORT */
break;
/* ----------------
case TBLOCK_END:
s->blockState = TBLOCK_DEFAULT;
AbortTransaction();
+ CleanupTransaction();
break;
/* ----------------
* 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;
}
}
/* ----------------
- * 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;
}
* 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;
}
* ----------------
*/
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");
* Get out of any low-level transaction
*/
if (s->state != TRANS_DEFAULT)
+ {
AbortTransaction();
+ CleanupTransaction();
+ }
/*
* Now reset the high-level state
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.87 2000/06/22 22:31:17 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.88 2000/06/28 03:31:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "miscadmin.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
+#include "utils/exc.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
-#include "utils/portal.h"
+
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
-extern void BaseInit(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(void);
extern void BootStrapXLOG(void);
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;
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
* ----------------
if (Typ == (struct typmap **) NULL)
{
- StartPortalAllocMode(DefaultAllocMode, 0);
rel = heap_openr(TypeRelationName, NoLock);
Assert(rel);
scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
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)
* 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);
*
*
* 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
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;
(int) MyProcPid, uniqueId++);
}
+ /* ----------------
+ * switch to the cache context to create the relcache entry.
+ * ----------------
+ */
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
+
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+
/* ----------------
* allocate a new relation descriptor.
* ----------------
/* ----------------
* have the storage manager create the relation.
+ *
+ * XXX shouldn't we switch out of CacheMemoryContext for that?
* ----------------
*/
*
*
* 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
* context changes
* ----------------
*/
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
* 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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.80 2000/06/15 04:09:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.81 2000/06/28 03:31:28 tgl Exp $
*
* NOTES
- * The PortalExecutorHeapMemory crap needs to be eliminated
- * by designing a better executor / portal processing memory
- * interface.
- *
* The PerformAddAttribute() code, like most of the relation
* manipulating code in the commands/ directory, should go
* someplace closer to the lib/catalog code.
#include "parser/parse.h"
#endif /* _DROP_COLUMN_HACK__ */
-/* ----------------
- * PortalExecutorHeapMemory stuff
- *
- * This is where the XXXSuperDuperHacky code was. -cim 3/15/90
- * ----------------
- */
-MemoryContext PortalExecutorHeapMemory = NULL;
/* --------------------------------
* PortalCleanup
void
PortalCleanup(Portal portal)
{
- MemoryContext context;
+ MemoryContext oldcontext;
/* ----------------
* sanity checks
* 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
* switch back to previous context
* ----------------
*/
- MemoryContextSwitchTo(context);
- PortalExecutorHeapMemory = (MemoryContext) NULL;
+ MemoryContextSwitchTo(oldcontext);
}
/* --------------------------------
Portal portal;
int feature;
QueryDesc *queryDesc;
- MemoryContext context;
+ MemoryContext oldcontext;
Const limcount;
/* ----------------
*/
if (name == NULL)
{
- elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
+ elog(NOTICE, "PerformPortalFetch: missing portal name");
return;
}
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
* 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
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
* execute the portal fetch operation
* ----------------
*/
- PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
-
ExecutorRun(queryDesc, PortalGetState(portal), feature,
(Node *) NULL, (Node *) &limcount);
if (dest == None) /* MOVE */
pfree(queryDesc);
+ /* ----------------
+ * Switch back to old context.
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldcontext);
+
/* ----------------
* Note: the "end-of-command" tag is returned by higher-level
* utility code
- *
- * Return blank portal for now.
- * Otherwise, this named portal will be cleaned.
- * Note: portals will only be supported within a BEGIN...END
- * block in the near future. Later, someone will fix it to
- * do what is possible across transaction boundries.
* ----------------
*/
- MemoryContextSwitchTo(
- (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
}
/* --------------------------------
*/
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
* ----------------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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)
* "ERROR" if table nonexistent.
* ...
*/
-extern Oid MyDatabaseId;
void
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,
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;
}
if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
{
- old = MemoryContextSwitchTo((MemoryContext) pmem);
+ old = MemoryContextSwitchTo(private_context);
if (relcnt == 0)
{
relalc = oncealc;
elog(NOTICE, "relation %d was reindexed", relids[i]);
CommitTransactionCommand();
}
- CommonSpecialPortalClose();
StartTransactionCommand();
+
+ MemoryContextDelete(private_context);
}
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
* as the current and return that.
* ----------
*/
- oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+ oldcxt = MemoryContextSwitchTo(deftrig_cxt);
trigstate = (DeferredTriggerStatus)
palloc(sizeof(DeferredTriggerStatusData));
int
DeferredTriggerInit(void)
{
- deftrig_gcxt = CreateGlobalMemory("DeferredTriggerSession");
+ deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
+ "DeferredTriggerSession",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+
return 0;
}
* 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;
deferredTriggerInvokeEvents(false);
- GlobalMemoryDestroy(deftrig_cxt);
+ MemoryContextDelete(deftrig_cxt);
deftrig_cxt = NULL;
}
if (deftrig_cxt == NULL)
return;
- GlobalMemoryDestroy(deftrig_cxt);
+ MemoryContextDelete(deftrig_cxt);
deftrig_cxt = NULL;
}
* ... outside of a transaction block
* ----------
*/
- oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
+ oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
/* ----------
* Drop all information about individual trigger states per
* ... inside of a transaction block
* ----------
*/
- oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+ oldcxt = MemoryContextSwitchTo(deftrig_cxt);
/* ----------
* Drop all information about individual trigger states per
* states of individual triggers on session level.
* ----------
*/
- oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
+ oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
foreach(l, loid)
{
* states of individual triggers on transaction level.
* ----------
*/
- oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+ oldcxt = MemoryContextSwitchTo(deftrig_cxt);
foreach(l, loid)
{
* 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];
* 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);
/*-------------------------------------------------------------------------
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*
*
* 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 $
*
*-------------------------------------------------------------------------
#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"
#endif
-bool CommonSpecialPortalInUse = false;
-
-static Portal vac_portal;
+static MemoryContext vac_context = NULL;
static int MESSAGE_LEVEL; /* message level */
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;
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)
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);
*/
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;
}
/*
TupleDesc tupdesc;
HeapScanDesc scan;
HeapTuple tuple;
- PortalVariableMemory portalmem;
- MemoryContext old;
VRelList vrl,
cur;
Datum d;
F_CHAREQ, CharGetDatum('r'));
}
- portalmem = CommonSpecialPortalGetMemory();
vrl = cur = (VRelList) NULL;
rel = heap_openr(RelationRelationName, AccessShareLock);
}
/* 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;
}
-/*
- * 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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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)
{
* 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 $
*
*-------------------------------------------------------------------------
*/
else
newVal = FunctionCallInvoke(&fcinfo);
if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
- pfree(peraggstate->value1);
+ pfree(DatumGetPointer(peraggstate->value1));
peraggstate->value1 = newVal;
peraggstate->value1IsNull = fcinfo.isnull;
}
else
newVal = FunctionCallInvoke(&fcinfo);
if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
- pfree(peraggstate->value2);
+ pfree(DatumGetPointer(peraggstate->value2));
peraggstate->value2 = newVal;
peraggstate->value2IsNull = fcinfo.isnull;
}
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));
}
/* ---------------------------------------
* Portions Copyright (c) 1994, Regents of the University of California
*
*
- * $Id: nodeHash.c,v 1.47 2000/06/15 04:09:52 momjian Exp $
+ * $Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecHash - generate an in-memory hash table of the relation
- * ExecInitHash - initialize node and subnodes..
+ * ExecInitHash - initialize node and subnodes
* ExecEndHash - shutdown node and subnodes
*
*/
#include
#include "postgres.h"
+
#include "executor/execdebug.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
#include "miscadmin.h"
-#include "utils/portal.h"
+
static int hashFunc(Datum key, int len, bool byVal);
int totalbuckets;
int bucketsize;
int i;
- Portal myPortal;
- char myPortalName[64];
MemoryContext oldcxt;
/* ----------------
hashtable->outerBatchSize = NULL;
/* ----------------
- * Create a named portal in which to keep the hashtable working storage.
- * Each hashjoin must have its own portal, so be wary of name conflicts.
+ * Create temporary memory contexts in which to keep the hashtable
+ * working storage. See notes in executor/hashjoin.h.
* ----------------
*/
- i = 0;
- do
- {
- i++;
- sprintf(myPortalName, "", i);
- myPortal = GetPortalByName(myPortalName);
- } while (PortalIsValid(myPortal));
- myPortal = CreatePortal(myPortalName);
- Assert(PortalIsValid(myPortal));
- hashtable->myPortal = (void *) myPortal; /* kluge for circular
- * includes */
- hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
- hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
+ hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
+ "HashTableContext",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+
+ hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
+ "HashBatchContext",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
/* Allocate data that will live for the life of the hashjoin */
}
/*
- * 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));
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);
/*
* 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
* 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);
int
SPI_connect()
{
- char pname[64];
- PortalVariableMemory pvmem;
-
- /*
- * It's possible on startup and after commit/abort. In future we'll
- * catch commit/abort in some way...
- */
- strcpy(pname, "");
- _SPI_portal = GetPortalByName(pname);
- if (!PortalIsValid(_SPI_portal))
- {
- if (_SPI_stack != NULL) /* there was abort */
- free(_SPI_stack);
- _SPI_current = _SPI_stack = NULL;
- _SPI_connected = _SPI_curid = -1;
- SPI_processed = 0;
- SPI_tuptable = NULL;
- _SPI_portal = CreatePortal(pname);
- if (!PortalIsValid(_SPI_portal))
- elog(FATAL, "SPI_connect: global initialization failed");
- }
-
/*
* When procedure called by Executor _SPI_curid expected to be equal
* to _SPI_connected
_SPI_current->processed = 0;
_SPI_current->tuptable = NULL;
- /* Create Portal for this procedure ... */
- snprintf(pname, 64, "", _SPI_connected);
- _SPI_current->portal = CreatePortal(pname);
- if (!PortalIsValid(_SPI_current->portal))
- elog(FATAL, "SPI_connect: initialization failed");
-
- /* ... and switch to Portal' Variable memory - procedure' context */
- pvmem = PortalGetVariableMemory(_SPI_current->portal);
- _SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
+ /* Create memory contexts for this procedure */
+ _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
+ "SPI Proc",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
+ "SPI Exec",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ /* ... and switch to procedure's context */
+ _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
_SPI_current->savedId = GetScanCommandId();
SetScanCommandId(GetCurrentCommandId());
/* 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);
{
free(_SPI_stack);
_SPI_stack = NULL;
+ _SPI_current = NULL;
}
else
{
}
+/*
+ * 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)
{
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 =================== */
argtypes = plan->argtypes;
}
- queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs, FALSE);
+ queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
_SPI_current->qtlist = queryTree_list;
_SPI_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;
#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);
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);
}
/*
if (execmem) /* switch to the Executor memory context */
{
_SPI_execmem();
- StartPortalAllocMode(DefaultAllocMode, 0);
}
return 0;
_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;
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);
else
newplan->argtypes = NULL;
- if (location != _SPI_CPLAN_CURCXT)
+ if (oldcxt != NULL)
MemoryContextSwitchTo(oldcxt);
return newplan;
# 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
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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);
-}
* 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 $
*
*-------------------------------------------------------------------------
*/
StringInfo res;
res = (StringInfo) palloc(sizeof(StringInfoData));
- if (res == NULL)
- elog(ERROR, "makeStringInfo: Out of memory");
initStringInfo(res);
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';
*
* 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)
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;
}
*
*
* 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
*
* Builtin functions for open/close/read/write operations on large objects.
*
- * These functions operate in a private GlobalMemoryContext, which means
+ * These functions operate in a private MemoryContext, which means
* that large object descriptors hang around until we destroy the context.
* That happens in lo_commit(). It'd be possible to prolong the lifetime
* of the context so that LO FDs are good across transactions (for example,
* But we'd need additional state in order to do the right thing at the
* end of an aborted transaction. FDs opened during an aborted xact would
* still need to be closed, since they might not be pointing at valid
- * relations at all. For now, we'll stick with the existing documented
- * semantics of LO FDs: they're only good within a transaction.
+ * relations at all. Locking semantics are also an interesting problem
+ * if LOs stay open across transactions. For now, we'll stick with the
+ * existing documented semantics of LO FDs: they're only good within a
+ * transaction.
*
*-------------------------------------------------------------------------
*/
*/
static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
-static GlobalMemory fscxt = NULL;
+static MemoryContext fscxt = NULL;
static int newLOfd(LargeObjectDesc *lobjCookie);
#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);
#endif
Assert(fscxt != NULL);
- currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+ currentContext = MemoryContextSwitchTo(fscxt);
inv_close(cookies[fd]);
}
Assert(fscxt != NULL);
- currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+ currentContext = MemoryContextSwitchTo(fscxt);
status = inv_read(cookies[fd], buf, len);
}
Assert(fscxt != NULL);
- currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+ currentContext = MemoryContextSwitchTo(fscxt);
status = inv_write(cookies[fd], buf, len);
}
Assert(fscxt != NULL);
- currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+ currentContext = MemoryContextSwitchTo(fscxt);
status = inv_seek(cookies[fd], offset, whence);
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);
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
MemoryContextSwitchTo(currentContext);
/* Release the LO memory context to prevent permanent memory leaks. */
- GlobalMemoryDestroy(fscxt);
+ MemoryContextDelete(fscxt);
fscxt = NULL;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* ----------------
* 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
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.15 2000/06/11 11:39:50 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.16 2000/06/28 03:31:41 tgl Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
#include "libpq/pqsignal.h"
+
+/*
+ * Initialize BlockSig and UnBlockSig.
+ *
+ * BlockSig is the set of signals to block when we are trying to block
+ * signals. This includes all signals we normally expect to get, but NOT
+ * signals that should never be turned off.
+ *
+ * UnBlockSig is the set of signals to block when we don't want to block
+ * signals (is this ever nonzero??)
+ */
+void
+pqinitmask(void)
+{
+#ifdef HAVE_SIGPROCMASK
+ sigemptyset(&UnBlockSig);
+ sigfillset(&BlockSig);
+ sigdelset(&BlockSig, SIGABRT);
+ sigdelset(&BlockSig, SIGILL);
+ sigdelset(&BlockSig, SIGSEGV);
+ sigdelset(&BlockSig, SIGBUS);
+ sigdelset(&BlockSig, SIGTRAP);
+ sigdelset(&BlockSig, SIGCONT);
+ sigdelset(&BlockSig, SIGSYS);
+#else
+ UnBlockSig = 0;
+ BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) |
+ sigmask(SIGTERM) | sigmask(SIGALRM) |
+ sigmask(SIGINT) | sigmask(SIGUSR1) |
+ sigmask(SIGUSR2) | sigmask(SIGCHLD) |
+ sigmask(SIGWINCH) | sigmask(SIGFPE);
+#endif
+}
+
+
+/*
+ * Set up a signal handler
+ */
pqsigfunc
pqsignal(int signo, pqsigfunc func)
{
* 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 $
*
*-------------------------------------------------------------------------
*/
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
-#include
-
#include "postgres.h"
+
+#include
#ifdef HAVE_LIMITS_H
#include
#else
#include "optimizer/geqo.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
-#include "utils/portal.h"
-
-
-/*
- * Variables set by geqo_eval_startup for use within a single GEQO run
- */
-static MemoryContext geqo_eval_context;
-
-/*
- * geqo_eval_startup:
- * Must be called during geqo_main startup (before geqo_eval may be called)
- *
- * The main thing we need to do here is prepare a private memory context for
- * allocation of temp storage used while constructing a path in geqo_eval().
- * Since geqo_eval() will be called many times, we can't afford to let all
- * that memory go unreclaimed until end of statement. We use a special
- * named portal to hold the context, so that it will be freed even if
- * we abort via elog(ERROR). The working data is allocated in the portal's
- * heap memory context.
- */
-void
-geqo_eval_startup(void)
-{
-#define GEQO_PORTAL_NAME ""
- Portal geqo_portal = GetPortalByName(GEQO_PORTAL_NAME);
-
- if (!PortalIsValid(geqo_portal))
- {
- /* First time through (within current transaction, that is) */
- geqo_portal = CreatePortal(GEQO_PORTAL_NAME);
- Assert(PortalIsValid(geqo_portal));
- }
+#include "utils/memutils.h"
- geqo_eval_context = (MemoryContext) PortalGetHeapMemory(geqo_portal);
-}
/*
* geqo_eval
Cost
geqo_eval(Query *root, Gene *tour, int num_gene)
{
+ MemoryContext mycontext;
MemoryContext oldcxt;
RelOptInfo *joinrel;
Cost fitness;
List *savelist;
- /* preserve root->join_rel_list, which gimme_tree changes */
- savelist = root->join_rel_list;
-
/*
- * create a temporary allocation context for the path construction
- * work
+ * Create a private memory context that will hold all temp storage
+ * allocated inside gimme_tree().
+ *
+ * Since geqo_eval() will be called many times, we can't afford to let
+ * all that memory go unreclaimed until end of statement. Note we make
+ * the temp context a child of TransactionCommandContext, so that
+ * it will be freed even if we abort via elog(ERROR).
*/
- oldcxt = MemoryContextSwitchTo(geqo_eval_context);
- StartPortalAllocMode(DefaultAllocMode, 0);
+ mycontext = AllocSetContextCreate(TransactionCommandContext,
+ "GEQO",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ oldcxt = MemoryContextSwitchTo(mycontext);
+
+ /* preserve root->join_rel_list, which gimme_tree changes */
+ savelist = root->join_rel_list;
/* construct the best path for the given combination of relations */
joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
root->join_rel_list = savelist;
/* release all the memory acquired within gimme_tree */
- EndPortalAllocMode();
MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(mycontext);
return fitness;
}
* 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 $
*
*-------------------------------------------------------------------------
*/
else
srandom(time(NULL));
-/* initialize plan evaluator */
- geqo_eval_startup();
-
/* allocate genetic pool memory */
pool = alloc_pool(pool_size, number_of_rels);
*
*
* 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
*
*/
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.
}
#endif
/* set up shared memory and semaphores */
- EnableMemoryContext(TRUE);
reset_shared(PostPortName);
/*
/*
* 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 */
/* Save port etc. for ps status */
MyProcPort = port;
+ /* Reset MyProcPid to new backend's pid */
MyProcPid = getpid();
/*
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 (",
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.46 2000/06/15 04:09:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.47 2000/06/28 03:31:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
-#include "lib/stringinfo.h"
+#include "utils/builtins.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_rewrite.h"
#include "parser/parse_relation.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteSupport.h"
-#include "tcop/tcopprot.h"
-Oid LastOidProcessed = InvalidOid;
-
-
-/*
- * Convert given string to a suitably quoted string constant,
- * and append it to the StringInfo buffer.
- * XXX Any MULTIBYTE considerations here?
- */
-static void
-quoteString(StringInfo buf, char *source)
-{
- char *current;
-
- appendStringInfoChar(buf, '\'');
- for (current = source; *current; current++)
- {
- char ch = *current;
-
- if (ch == '\'' || ch == '\\')
- {
- appendStringInfoChar(buf, '\\');
- appendStringInfoChar(buf, ch);
- }
- else if (ch >= 0 && ch < ' ')
- appendStringInfo(buf, "\\%03o", (int) ch);
- else
- appendStringInfoChar(buf, ch);
- }
- appendStringInfoChar(buf, '\'');
-}
/*
* InsertRule -
* takes the arguments and inserts them as attributes into the system
* relation "pg_rewrite"
*
- * MODS : changes the value of LastOidProcessed as a side
- * effect of inserting the rule tuple
- *
* ARGS : rulname - name of the rule
* evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
* evobj - name of relation
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);
evslot_index = attnameAttNum(eventrel, evslot);
heap_close(eventrel, AccessShareLock);
- if (evinstead)
- is_instead = "t";
-
if (evqual == NULL)
evqual = "<>";
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
rulname);
- initStringInfo(&rulebuf);
- appendStringInfo(&rulebuf,
- "INSERT INTO pg_rewrite (rulename, ev_type, ev_class, ev_attr, ev_action, ev_qual, is_instead) VALUES (");
- quoteString(&rulebuf, rulname);
- appendStringInfo(&rulebuf, ", %d::char, %u::oid, %d::int2, ",
- evtype, eventrel_oid, evslot_index);
- quoteString(&rulebuf, actiontree);
- appendStringInfo(&rulebuf, "::text, ");
- quoteString(&rulebuf, evqual);
- appendStringInfo(&rulebuf, "::text, '%s'::bool);",
- is_instead);
+ /* ----------------
+ * Set up *nulls and *values arrays
+ * ----------------
+ */
+ MemSet(nulls, ' ', sizeof(nulls));
+
+ i = 0;
+ namestrcpy(&rname, rulname);
+ values[i++] = NameGetDatum(&rname);
+ values[i++] = CharGetDatum(evtype + '0');
+ values[i++] = ObjectIdGetDatum(eventrel_oid);
+ values[i++] = Int16GetDatum(evslot_index);
+ values[i++] = BoolGetDatum(evinstead);
+ values[i++] = PointerGetDatum(lztextin(evqual));
+ values[i++] = PointerGetDatum(lztextin(actiontree));
+
+ /* ----------------
+ * create a new pg_rewrite tuple
+ * ----------------
+ */
+ pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
+
+ tupDesc = pg_rewrite_desc->rd_att;
+
+ tup = heap_formtuple(tupDesc,
+ values,
+ nulls);
+
+ heap_insert(pg_rewrite_desc, tup);
+
+ rewriteObjectId = tup->t_data->t_oid;
+
+ if (RelationGetForm(pg_rewrite_desc)->relhasindex)
+ {
+ Relation idescs[Num_pg_rewrite_indices];
+
+ CatalogOpenIndices(Num_pg_rewrite_indices, Name_pg_rewrite_indices,
+ idescs);
+ CatalogIndexInsert(idescs, Num_pg_rewrite_indices, pg_rewrite_desc,
+ tup);
+ CatalogCloseIndices(Num_pg_rewrite_indices, idescs);
+ }
- pg_exec_query_dest(rulebuf.data, None, true);
+ heap_freetuple(tup);
- pfree(rulebuf.data);
+ heap_close(pg_rewrite_desc, RowExclusiveLock);
- return LastOidProcessed;
+ return rewriteObjectId;
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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);
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 *));
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);
break;
}
Assert(i < numlock);
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
pfree(rulelock->rules[i]);
MemoryContextSwitchTo(oldcxt);
if (numlock == 1)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
/*
- * 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);
tmpFree = *ShmemFreeStart + size;
if (tmpFree <= ShmemSize)
{
- newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
+ newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
*ShmemFreeStart += size;
}
else
SpinRelease(ShmemLock);
if (!newSpace)
- elog(NOTICE, "ShmemAlloc: out of memory ");
+ elog(NOTICE, "ShmemAlloc: out of memory");
+
return newSpace;
}
int hash_flags) /* info about infoP */
{
bool found;
- long *location;
+ void *location;
/*
* Hash tables allocated in shared memory have a fixed directory; it
* 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;
#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);
}
/* 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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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));
*
*
* 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
* 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,
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
*/
SpinAcquire(LockMgrLock);
-
/* -----------------------
* allocate a control structure from shared memory or attach to it
* if it already exists.
*/
sprintf(shmemName, "%s (ctl)", tabName);
lockMethodTable->ctl = (LOCKMETHODCTL *)
- ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found);
+ ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
if (!lockMethodTable->ctl)
{
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* This is so that we can support more backends. (system-wide semaphore
* sets run out pretty fast.) -ay 4/95
*
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
*/
#include
#include
/* 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.
/* 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. */
* cleanup dead processes).
*/
- MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
+ MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
if (!MyProc)
{
SpinRelease(ProcStructLock);
{
bool found;
PROC_QUEUE *queue = (PROC_QUEUE *)
- ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
+ ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
if (!queue)
return NULL;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
int
mdinit()
{
- MemoryContext oldcxt;
int i;
- MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
- if (MdCxt == (MemoryContext) NULL)
- return SM_FAIL;
-
- oldcxt = MemoryContextSwitchTo(MdCxt);
- Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
- MemoryContextSwitchTo(oldcxt);
+ MdCxt = AllocSetContextCreate(TopMemoryContext,
+ "MdSmgr",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
- if (Md_fdvec == (MdfdVec *) NULL)
- return SM_FAIL;
+ Md_fdvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
int nblocks;
int fd;
MdfdVec *v;
- MemoryContext oldcxt;
/*
* If the relation is already unlinked,we have nothing to do any more.
Md_fdvec[fd].mdfd_flags = (uint16) 0;
- oldcxt = MemoryContextSwitchTo(MdCxt);
#ifndef LET_OS_MANAGE_FILESIZE
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
{
FileTruncate(v->mdfd_vfd, 0);
FileUnlink(v->mdfd_vfd);
#endif
- MemoryContextSwitchTo(oldcxt);
_fdvec_free(fd);
mdclose_fd(int fd)
{
MdfdVec *v;
- MemoryContext oldcxt;
- oldcxt = MemoryContextSwitchTo(MdCxt);
#ifndef LET_OS_MANAGE_FILESIZE
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
{
}
}
#endif
- MemoryContextSwitchTo(oldcxt);
_fdvec_free(fd);
}
int curnblk;
int fd;
MdfdVec *v;
-
#ifndef LET_OS_MANAGE_FILESIZE
- MemoryContext oldcxt;
int priorblocks;
-
#endif
/*
v = &Md_fdvec[fd];
#ifndef LET_OS_MANAGE_FILESIZE
- oldcxt = MemoryContextSwitchTo(MdCxt);
priorblocks = 0;
while (v != (MdfdVec *) NULL)
{
}
priorblocks += RELSEG_SIZE;
}
- MemoryContextSwitchTo(oldcxt);
#else
if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
return -1;
#endif
return nblocks;
-
-} /* mdtruncate */
+}
/*
* mdcommit() -- Commit a transaction.
MdfdVec *nvec;
int fdvec,
i;
- MemoryContext oldcxt;
if (Md_Free >= 0) /* get from free list */
{
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 */
static MdfdVec *
_mdfd_openseg(Relation reln, int segno, int oflags)
{
- MemoryContext oldcxt;
MdfdVec *v;
int fd;
char *path,
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;
*
*
* 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
CommandDest whereToSendOutput = Debug;
-extern void BaseInit(void);
extern void StartupXLOG(void);
extern void ShutdownXLOG(void);
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 */
bool InError = false;
bool ExitAfterAbort = false;
-extern int NBuffers;
-
static bool EchoQuery = false; /* default don't echo */
char pg_pathname[MAXPGPATH];
FILE *StatFp = NULL;
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);
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;
}
* 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;
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)
/* ----------------------------------------------------------------
- * pg_exec_query()
+ * pg_exec_query_dest()
*
* Takes a querystring, runs the parser/utilities or
- * parser/planner/executor over it as necessary
- * Begin Transaction Should have been called before this
- * and CommitTransaction After this is called
- * This is strictly because we do not allow for nested xactions.
+ * parser/planner/executor over it as necessary.
+ *
+ * Assumptions:
+ *
+ * Caller is responsible for calling StartTransactionCommand() beforehand
+ * and CommitTransactionCommand() afterwards (if successful).
+ *
+ * The CurrentMemoryContext at entry references a context that is
+ * appropriate for execution of individual queries (typically this will be
+ * TransactionCommandContext). Note that this routine resets that context
+ * after each individual query, so don't store anything there that
+ * must outlive the call!
*
- * NON-OBVIOUS-RESTRICTIONS
- * this function _MUST_ allocate a new "parsetree" each time,
- * since it may be stored in a named portal and should not
- * change its value.
+ * parse_context references a context suitable for holding the
+ * parse/rewrite trees (typically this will be QueryContext).
+ * This context must be longer-lived than the CurrentMemoryContext!
+ * In fact, if the query string might contain BEGIN/COMMIT commands,
+ * parse_context had better outlive TopTransactionContext!
+ *
+ * We could have hard-wired knowledge about QueryContext and
+ * TransactionCommandContext into this routine, but it seems better
+ * not to, in case callers from outside this module need to use some
+ * other contexts.
*
* ----------------------------------------------------------------
*/
-static void
-pg_exec_query(char *query_string)
-{
- pg_exec_query_dest(query_string, whereToSendOutput, FALSE);
-}
-
-#ifdef NOT_USED
-void
-pg_exec_query_acl_override(char *query_string)
-{
- pg_exec_query_dest(query_string, whereToSendOutput, TRUE);
-}
-#endif
-
void
pg_exec_query_dest(char *query_string, /* string to execute */
CommandDest dest, /* where results should go */
- bool aclOverride) /* to give utility commands power
- * of superusers */
+ MemoryContext parse_context) /* context for parsetrees */
{
- List *querytree_list;
+ MemoryContext oldcontext;
+ List *querytree_list,
+ *querytree_item;
- /* parse and rewrite the queries */
- querytree_list = pg_parse_and_rewrite(query_string, NULL, 0,
- aclOverride);
+ /*
+ * Switch to appropriate context for constructing parsetrees.
+ */
+ oldcontext = MemoryContextSwitchTo(parse_context);
/*
- * NOTE: we do not use "foreach" here because we want to be sure the
- * list pointer has been advanced before the query is executed. We
- * need to do that because VACUUM has a nasty little habit of doing
- * CommitTransactionCommand at startup, and that will release the
- * memory holding our parse list :-(. This needs a better solution
- * --- currently, the code will crash if someone submits "vacuum;
- * something-else" in a single query string. But memory allocation
- * needs redesigned anyway, so this will have to do for now.
+ * Parse and rewrite the query or queries.
*/
- while (querytree_list)
- {
- Query *querytree = (Query *) lfirst(querytree_list);
+ querytree_list = pg_parse_and_rewrite(query_string, NULL, 0);
- querytree_list = lnext(querytree_list);
+ /*
+ * Switch back to execution context for planning and execution.
+ */
+ MemoryContextSwitchTo(oldcontext);
+
+ /*
+ * Run through the query or queries and execute each one.
+ */
+ foreach(querytree_item, querytree_list)
+ {
+ Query *querytree = (Query *) lfirst(querytree_item);
/* if we got a cancel signal in parsing or prior command, quit */
if (QueryCancel)
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)
{
* 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);
}
}
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.
*/
break;
case 'i':
- dontExecute = 1;
+ dontExecute = true;
break;
case 'L':
*
* 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);
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 */
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
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.
*/
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");
}
/*
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
*
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) */
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 */
* (3) read a command (loop blocks here)
* ----------------
*/
+ set_ps_display("idle");
+
firstchar = ReadCommand(parser_input);
QueryCancel = false; /* forget any earlier CANCEL signal */
elog(DEBUG, "StartTransactionCommand");
StartTransactionCommand();
- pg_exec_query(parser_input->data);
+ pg_exec_query_dest(parser_input->data,
+ whereToSendOutput,
+ QueryContext);
/*
* Invoke IMMEDIATE constraint triggers
* (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)
#ifdef SHOW_MEMORY_STATS
/* print global-context stats at each commit for leak tracking */
if (ShowStats)
- GlobalMemoryStats();
+ MemoryContextStats(TopMemoryContext);
#endif
}
else
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "utils/ps_status.h"
static char *CreateOperationTag(int operationType);
-static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
- Node *limcount);
/* ----------------------------------------------------------------
default:
elog(DEBUG, "CreateOperationTag: unknown operation type %d",
operationType);
- tag = NULL;
+ tag = "???";
break;
}
}
/* ----------------
- * 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))
{
}
/* ----------------
- * Convert the current blank portal into the user-specified
- * portal and initialize the state and query descriptor.
- *
- * Since the parsetree has been created in the current blank portal,
- * we don't have to do any work to copy it into the user-named portal.
+ * Create the new portal and make its memory context active.
* ----------------
*/
+ portal = CreatePortal(portalName);
- portal = BlankPortalAssignName(portalName);
-
- PortalSetQuery(portal,
- CreateQueryDesc(parseTree, plan, dest),
- attinfo,
- state,
- PortalCleanup);
+ MemoryContextSwitchTo(PortalGetHeapMemory(portal));
- /* ----------------
- * Now create a new blank portal and switch to it.
- * Otherwise, the new named portal will be cleaned at statement end.
- *
- * Note: portals will only be supported within a BEGIN...END
- * block in the near future. Later, someone will fix it to
- * do what is possible across transaction boundries. -hirohama
- * ----------------
- */
- portalContext = (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL));
-
- MemoryContextSwitchTo(portalContext);
-
- StartPortalAllocMode(DefaultAllocMode, 0);
+ return portal;
}
/* ----------------------------------------------------------------
- * ProcessQueryDesc
+ * ProcessQuery
*
- * Read the comments for ProcessQuery() below...
+ * Execute a plan, the non-parallel version
* ----------------------------------------------------------------
*/
-static void
-ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
+void
+ProcessQuery(Query *parsetree,
+ Plan *plan,
+ CommandDest dest)
{
- Query *parseTree;
- Plan *plan;
- int operation;
- char *tag = NULL;
- EState *state;
- TupleDesc attinfo;
-
+ int operation = parsetree->commandType;
+ char *tag;
bool isRetrieveIntoPortal;
bool isRetrieveIntoRelation;
+ Portal portal = NULL;
char *intoName = NULL;
- CommandDest dest;
-
- /* ----------------
- * get info from the query desc
- * ----------------
- */
- parseTree = queryDesc->parsetree;
- plan = queryDesc->plantree;
+ QueryDesc *queryDesc;
+ EState *state;
+ TupleDesc attinfo;
- operation = queryDesc->operation;
set_ps_display(tag = CreateOperationTag(operation));
- dest = queryDesc->dest;
/* ----------------
* initialize portal/into relation status
if (operation == CMD_SELECT)
{
- if (parseTree->isPortal)
+ if (parsetree->isPortal)
{
isRetrieveIntoPortal = true;
- intoName = parseTree->into;
- if (parseTree->isBinary)
+ intoName = parsetree->into;
+ if (parsetree->isBinary)
{
/*
* (externalized form) to RemoteInternal (internalized
* form)
*/
- dest = queryDesc->dest = RemoteInternal;
+ dest = RemoteInternal;
}
}
- else if (parseTree->into != NULL)
+ else if (parsetree->into != NULL)
{
/* select into table */
isRetrieveIntoRelation = true;
}
+ }
+ /* ----------------
+ * If retrieving into a portal, set up the portal and copy
+ * the parsetree and plan into its memory context.
+ * ----------------
+ */
+ if (isRetrieveIntoPortal)
+ {
+ portal = PreparePortal(intoName);
+ /* CurrentMemoryContext is now pointing to portal's context */
+ parsetree = copyObject(parsetree);
+ plan = copyObject(plan);
}
/* ----------------
- * when performing a retrieve into, we override the normal
+ * Now we can create the QueryDesc object (this is also in
+ * the portal context, if portal retrieve).
+ * ----------------
+ */
+ queryDesc = CreateQueryDesc(parsetree, plan, dest);
+
+ /* ----------------
+ * When performing a retrieve into, we override the normal
* communication destination during the processing of the
* the query. This only affects the tuple-output function
* - the correct destination will still see BeginCommand()
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;
* 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);
*/
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);
-}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
}
+/*
+ * 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
* --------------------------------
* 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
/* --------------------------------
* CatCacheRemoveCTup
*
- * NB: assumes caller has switched to CacheCxt
+ * NB: assumes caller has switched to CacheMemoryContext
* --------------------------------
*/
static void
* 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
* 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
* 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
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);
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);
CatCTup *nct2;
Dlelem *elt;
HeapTuple ntp = NULL;
-
Relation relation;
MemoryContext oldcxt;
* ----------------
*/
- 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
*/
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
{
ntp = heap_getnext(sd, 0);
- MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ MemoryContextSwitchTo(CacheMemoryContext);
if (HeapTupleIsValid(ntp))
{
heap_endscan(sd);
- MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ MemoryContextSwitchTo(CacheMemoryContext);
}
cache->busy = false;
* switch to the cache memory context
* ----------------
*/
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
+
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* for each cache
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* ----------------
* 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;
if (relation->rd_isnailed)
return;
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/*
* Remove relation from hash tables
List *curr;
List *prev = NIL;
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
foreach(curr, newlyCreatedRelns)
{
{
MemoryContext oldcxt;
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
-
- if (oldcxt != (MemoryContext) CacheCxt)
- elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
RelationInitLockInfo(relation);
if (newlyCreatedRelns == NULL)
return;
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
while (newlyCreatedRelns)
{
* switch to cache memory context
* ----------------
*/
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
+ if (!CacheMemoryContext)
+ CreateCacheMemoryContext();
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
/* ----------------
* create global caches
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
List *l,
*prev;
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
prev = NIL;
l = temp_rels;
List *l,
*prev;
- oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
prev = NIL;
l = temp_rels;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include
#include
#ifdef ENABLE_SYSLOG
-# include
+#include
#endif
#include "libpq/libpq.h"
*--------------------
*/
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
* 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;
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;
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... */
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;
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! */
}
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;
}
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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);
static int hdefault(HTAB *hashp);
static int init_htab(HTAB *hashp, int nelem);
-typedef long *((*dhalloc_ptr) ());
-#ifndef FRONTEND
/* ----------------
* memory allocation routines
*
* 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
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)
/* setup hash table defaults */
hashp->hctl = NULL;
- hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
+ hashp->alloc = MEM_ALLOC;
hashp->dir = NULL;
hashp->segbase = NULL;
if (!hashp->hctl)
{
- hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
+ hashp->hctl = (HHDR *) hashp->alloc(sizeof(HHDR));
if (!hashp->hctl)
return 0;
}
/* 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;
}
/* 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);
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)
{
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;
/* 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;
# 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
ifeq (depend,$(wildcard depend))
include depend
endif
-
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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);
-}
*
*
* 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 $
*
*
*-------------------------------------------------------------------------
#include "mb/pg_wchar.h"
#endif
-void BaseInit(void);
-
static void ReverifyMyDatabase(const char *name);
static void InitCommunication(void);
* Be very careful with the order of calls in the InitPostgres function.
* --------------------------------
*/
-extern int NBuffers;
-
int lockingOff = 0; /* backend -L switch */
/*
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.
InitCommunication();
DebugFileOpen();
smgrinit();
+
+ EnablePortalManager(); /* memory for portal/transaction stuff */
}
* 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 $
*
*
*/
};
#ifdef DEBUGMAIN
-#include "utils/mcxt.h"
+#include "postgres.h"
+#include "utils/memutils.h"
/*
* testing for sjis2mic() and mic2sjis()
*/
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
# 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
--- /dev/null
+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.
* aset.c
* Allocation set definitions.
*
+ * AllocSet is our standard implementation of the abstract MemoryContext
+ * type.
+ *
+ *
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- *
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.27 2000/05/21 02:23:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.28 2000/06/28 03:32:50 tgl Exp $
*
* NOTE:
* This is a new (Feb. 05, 1999) implementation of the allocation set
* AllocSetReset() under the old way.
*-------------------------------------------------------------------------
*/
+
#include "postgres.h"
+
#include "utils/memutils.h"
-#undef AllocSetReset
-#undef malloc
-#undef free
-#undef realloc
+/*
+ * AllocSetContext is defined in nodes/memnodes.h.
+ */
+typedef AllocSetContext *AllocSet;
+
+/*
+ * AllocPointer
+ * Aligned pointer which may be a member of an allocation set.
+ */
+typedef void *AllocPointer;
+
+/*
+ * AllocBlock
+ * An AllocBlock is the unit of memory that is obtained by aset.c
+ * from malloc(). It contains one or more AllocChunks, which are
+ * the units requested by palloc() and freed by pfree(). AllocChunks
+ * cannot be returned to malloc() individually, instead they are put
+ * on freelists by pfree() and re-used by the next palloc() that has
+ * a matching request size.
+ *
+ * AllocBlockData is the header data for a block --- the usable space
+ * within the block begins at the next alignment boundary.
+ */
+typedef struct AllocBlockData
+{
+ AllocSet aset; /* aset that owns this block */
+ AllocBlock next; /* next block in aset's blocks list */
+ char *freeptr; /* start of free space in this block */
+ char *endptr; /* end of space in this block */
+} AllocBlockData;
+
+/*
+ * AllocChunk
+ * The prefix of each piece of memory in an AllocBlock
+ *
+ * NB: this MUST match StandardChunkHeader as defined by utils/memutils.h.
+ */
+typedef struct AllocChunkData
+{
+ /* aset is the owning aset if allocated, or the freelist link if free */
+ void *aset;
+ /* size is always the size of the usable space in the chunk */
+ Size size;
+} AllocChunkData;
+/*
+ * AllocPointerIsValid
+ * True iff pointer is valid allocation pointer.
+ */
+#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
+
+/*
+ * AllocSetIsValid
+ * True iff set is valid allocation set.
+ */
+#define AllocSetIsValid(set) PointerIsValid(set)
/*--------------------
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
/* Size of largest chunk that we use a fixed size for */
/*--------------------
- * The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
+ * The first block allocated for an allocset has size initBlockSize.
* Each time we have to allocate another block, we double the block size
- * (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
+ * (if possible, and without exceeding maxBlockSize), so as to reduce
* the bookkeeping load on malloc().
*
* Blocks allocated to hold oversize chunks do not follow this rule, however;
* AllocSetAlloc has discretion whether to put the request into an existing
* block or make a single-chunk block.
*
- * We must have ALLOC_MIN_BLOCK_SIZE > ALLOC_SMALLCHUNK_LIMIT and
+ * We must have initBlockSize > ALLOC_SMALLCHUNK_LIMIT and
* ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
*--------------------
*/
-#define ALLOC_MIN_BLOCK_SIZE (8 * 1024)
-#define ALLOC_MAX_BLOCK_SIZE (8 * 1024 * 1024)
-
#define ALLOC_BIGCHUNK_LIMIT (64 * 1024)
/* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
+/* Min safe value of allocation block size */
+#define ALLOC_MIN_BLOCK_SIZE \
+ (ALLOC_SMALLCHUNK_LIMIT + ALLOC_CHUNKHDRSZ + ALLOC_BLOCKHDRSZ)
+
#define AllocPointerGetChunk(ptr) \
((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
#define AllocChunkGetPointer(chk) \
#define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
#define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size)
+/*
+ * These functions implement the MemoryContext API for AllocSet contexts.
+ */
+static void *AllocSetAlloc(MemoryContext context, Size size);
+static void AllocSetFree(MemoryContext context, void *pointer);
+static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
+static void AllocSetInit(MemoryContext context);
+static void AllocSetReset(MemoryContext context);
+static void AllocSetDelete(MemoryContext context);
+static void AllocSetStats(MemoryContext context);
+
+/*
+ * This is the virtual function table for AllocSet contexts.
+ */
+static MemoryContextMethods AllocSetMethods = {
+ AllocSetAlloc,
+ AllocSetFree,
+ AllocSetRealloc,
+ AllocSetInit,
+ AllocSetReset,
+ AllocSetDelete,
+ AllocSetStats
+};
/* ----------
* Public routines
*/
+
/*
- * AllocSetInit
- * Initializes given allocation set.
- *
- * Note:
- * The semantics of the mode are explained above. Limit is ignored
- * for dynamic and static modes.
+ * AllocSetContextCreate
+ * Create a new AllocSet context.
*
- * Exceptions:
- * BadArg if set is invalid pointer.
- * BadArg if mode is invalid.
+ * parent: parent context, or NULL if top-level context
+ * name: name of context (for debugging --- string will be copied)
+ * minContextSize: minimum context size
+ * initBlockSize: initial allocation block size
+ * maxBlockSize: maximum allocation block size
*/
-void
-AllocSetInit(AllocSet set, AllocMode mode, Size limit)
+MemoryContext
+AllocSetContextCreate(MemoryContext parent,
+ const char *name,
+ Size minContextSize,
+ Size initBlockSize,
+ Size maxBlockSize)
{
- AssertArg(PointerIsValid(set));
- AssertArg((int) DynamicAllocMode <= (int) mode);
- AssertArg((int) mode <= (int) BoundedAllocMode);
+ AllocSet context;
+
+ /* Do the type-independent part of context creation */
+ context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
+ sizeof(AllocSetContext),
+ &AllocSetMethods,
+ parent,
+ name);
+ /*
+ * Make sure alloc parameters are safe, and save them
+ */
+ initBlockSize = MAXALIGN(initBlockSize);
+ if (initBlockSize < ALLOC_MIN_BLOCK_SIZE)
+ initBlockSize = ALLOC_MIN_BLOCK_SIZE;
+ maxBlockSize = MAXALIGN(maxBlockSize);
+ if (maxBlockSize < initBlockSize)
+ maxBlockSize = initBlockSize;
+ context->initBlockSize = initBlockSize;
+ context->maxBlockSize = maxBlockSize;
/*
- * XXX mode is currently ignored and treated as DynamicAllocMode. XXX
- * limit is also ignored. This affects this whole file.
+ * Grab always-allocated space, if requested
*/
+ if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)
+ {
+ Size blksize = MAXALIGN(minContextSize);
+ AllocBlock block;
- memset(set, 0, sizeof(AllocSetData));
+ block = (AllocBlock) malloc(blksize);
+ if (block == NULL)
+ elog(ERROR, "Memory exhausted in AllocSetContextCreate()");
+ block->aset = context;
+ block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
+ block->endptr = ((char *) block) + blksize;
+ block->next = context->blocks;
+ context->blocks = block;
+ /* Mark block as not to be released at reset time */
+ context->keeper = block;
+ }
+
+ return (MemoryContext) context;
}
+/*
+ * AllocSetInit
+ * Context-type-specific initialization routine.
+ *
+ * This is called by MemoryContextCreate() after setting up the
+ * generic MemoryContext fields and before linking the new context
+ * into the context tree. We must do whatever is needed to make the
+ * new context minimally valid for deletion. We must *not* risk
+ * failure --- thus, for example, allocating more memory is not cool.
+ * (AllocSetContextCreate can allocate memory when it gets control
+ * back, however.)
+ */
+static void
+AllocSetInit(MemoryContext context)
+{
+ /*
+ * Since MemoryContextCreate already zeroed the context node,
+ * we don't have to do anything here: it's already OK.
+ */
+}
/*
* AllocSetReset
* Frees all memory which is allocated in the given set.
*
- * Exceptions:
- * BadArg if set is invalid.
+ * Actually, this routine has some discretion about what to do.
+ * It should mark all allocated chunks freed, but it need not
+ * necessarily give back all the resources the set owns. Our
+ * actual implementation is that we hang on to any "keeper"
+ * block specified for the set.
*/
-void
-AllocSetReset(AllocSet set)
+static void
+AllocSetReset(MemoryContext context)
{
+ AllocSet set = (AllocSet) context;
AllocBlock block = set->blocks;
- AllocBlock next;
AssertArg(AllocSetIsValid(set));
while (block != NULL)
{
- next = block->next;
+ AllocBlock next = block->next;
+
+ if (block == set->keeper)
+ {
+ /* Reset the block, but don't return it to malloc */
+ block->next = NULL;
+ block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
#ifdef CLOBBER_FREED_MEMORY
- /* Wipe freed memory for debugging purposes */
- memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+ /* Wipe freed memory for debugging purposes */
+ memset(block->freeptr, 0x7F,
+ ((char *) block->endptr) - ((char *) block->freeptr));
#endif
- free(block);
+ }
+ else
+ {
+ /* Normal case, release the block */
+#ifdef CLOBBER_FREED_MEMORY
+ /* Wipe freed memory for debugging purposes */
+ memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+#endif
+ free(block);
+ }
block = next;
}
- memset(set, 0, sizeof(AllocSetData));
+ /* Now blocks list is either empty or just the keeper block */
+ set->blocks = set->keeper;
+ /* Clear chunk freelists in any case */
+ MemSet(set->freelist, 0, sizeof(set->freelist));
}
/*
- * AllocSetContains
- * True iff allocation set contains given allocation element.
+ * AllocSetDelete
+ * Frees all memory which is allocated in the given set,
+ * in preparation for deletion of the set.
*
- * Exceptions:
- * BadArg if set is invalid.
- * BadArg if pointer is invalid.
+ * Unlike AllocSetReset, this *must* free all resources of the set.
+ * But note we are not responsible for deleting the context node itself.
*/
-bool
-AllocSetContains(AllocSet set, AllocPointer pointer)
+static void
+AllocSetDelete(MemoryContext context)
{
+ AllocSet set = (AllocSet) context;
+ AllocBlock block = set->blocks;
+
AssertArg(AllocSetIsValid(set));
- AssertArg(AllocPointerIsValid(pointer));
- return (AllocPointerGetAset(pointer) == set);
+ while (block != NULL)
+ {
+ AllocBlock next = block->next;
+
+#ifdef CLOBBER_FREED_MEMORY
+ /* Wipe freed memory for debugging purposes */
+ memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+#endif
+ free(block);
+ block = next;
+ }
+
+ /* Make it look empty, just in case... */
+ set->blocks = NULL;
+ MemSet(set->freelist, 0, sizeof(set->freelist));
+ set->keeper = NULL;
}
/*
* AllocSetAlloc
* Returns pointer to allocated memory of given size; memory is added
* to the set.
- *
- * Exceptions:
- * BadArg if set is invalid.
- * MemoryExhausted if allocation fails.
*/
-AllocPointer
-AllocSetAlloc(AllocSet set, Size size)
+static void *
+AllocSetAlloc(MemoryContext context, Size size)
{
+ AllocSet set = (AllocSet) context;
AllocBlock block;
AllocChunk chunk;
AllocChunk priorfree = NULL;
/*
* 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)
/*
* 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)
{
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;
{
if (set->blocks == NULL)
{
- blksize = ALLOC_MIN_BLOCK_SIZE;
+ blksize = set->initBlockSize;
block = (AllocBlock) malloc(blksize);
}
else
/*
* 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);
}
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;
/*
* 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 */
* 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.)
*/
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 */
/* 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;
AllocChunk chunk;
int fidx;
- AssertArg(AllocSetIsValid(set));
-
for (block = set->blocks; block != NULL; block = block->next)
{
nblocks++;
}
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);
}
/*-------------------------------------------------------------------------
*
* mcxt.c
- * POSTGRES memory context code.
+ * POSTGRES memory context management code.
+ *
+ * This module handles context management operations that are independent
+ * of the particular kind of context being operated on. It calls
+ * context-type-specific operations via the function pointers in a
+ * context's MemoryContextMethods struct.
+ *
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.21 2000/05/21 02:23:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.22 2000/06/28 03:32:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/memnodes.h"
#include "utils/excid.h"
-#include "utils/module.h"
-
-
-
-#undef MemoryContextAlloc
-#undef MemoryContextFree
-#undef malloc
-#undef free
-
-/*
- * Global State
- */
-static int MemoryContextEnableCount = 0;
-
-#define MemoryContextEnabled (MemoryContextEnableCount > 0)
+#include "utils/memutils.h"
-static OrderedSetData ActiveGlobalMemorySetData; /* uninitialized */
-
-#define ActiveGlobalMemorySet (&ActiveGlobalMemorySetData)
-
-/*
- * description of allocated memory representation goes here
- */
-
-#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
-#define PSIZEALL(PTR) (*((int32 *)(PTR) - 1) + sizeof (int32))
-#define PSIZESKIP(PTR) ((char *)((int32 *)(PTR) + 1))
-#define PSIZEFIND(PTR) ((char *)((int32 *)(PTR) - 1))
-#define PSIZESPACE(LEN) ((LEN) + sizeof (int32))
-
-/*
- * AllocSizeIsValid
- * True iff 0 < size and size <= MaxAllocSize.
- */
-#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
/*****************************************************************************
* GLOBAL MEMORY *
/*
* CurrentMemoryContext
- * Memory context for general global allocations.
+ * Default memory context for allocations.
*/
DLLIMPORT MemoryContext CurrentMemoryContext = NULL;
-/*****************************************************************************
- * PRIVATE DEFINITIONS *
- *****************************************************************************/
-
-static Pointer GlobalMemoryAlloc(GlobalMemory this, Size size);
-static void GlobalMemoryFree(GlobalMemory this, Pointer pointer);
-static Pointer GlobalMemoryRealloc(GlobalMemory this, Pointer pointer,
- Size size);
-static char *GlobalMemoryGetName(GlobalMemory this);
-static void GlobalMemoryDump(GlobalMemory this);
-
-#ifdef NOT_USED
-static void DumpGlobalMemories(void);
-
-#endif
-
/*
- * Global Memory Methods
+ * Standard top-level contexts
*/
+MemoryContext TopMemoryContext = NULL;
+MemoryContext ErrorContext = NULL;
+MemoryContext PostmasterContext = NULL;
+MemoryContext CacheMemoryContext = NULL;
+MemoryContext QueryContext = NULL;
+MemoryContext TopTransactionContext = NULL;
+MemoryContext TransactionCommandContext = NULL;
-static struct MemoryContextMethodsData GlobalContextMethodsData = {
- GlobalMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
- GlobalMemoryFree, /* void (*)(this, Pointer) pfree */
- GlobalMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
- GlobalMemoryGetName, /* char* (*)(this) getName */
- GlobalMemoryDump /* void (*)(this) dump */
-};
-/*
- * Note:
- * TopGlobalMemory is handled specially because of bootstrapping.
- */
-/* extern bool EqualGlobalMemory(); */
+/*****************************************************************************
+ * EXPORTED ROUTINES *
+ *****************************************************************************/
-static struct GlobalMemoryData TopGlobalMemoryData = {
- T_GlobalMemory, /* NodeTag tag */
- &GlobalContextMethodsData, /* ContextMethods method */
- {NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
- /* free AllocSet */
- "TopGlobal", /* char* name */
- {0} /* uninitialized OrderedElemData elemD */
-};
/*
- * TopMemoryContext
- * Memory context for general global allocations.
+ * MemoryContextInit
+ * Start up the memory-context subsystem.
*
- * Note:
- * Don't use this memory context for random allocations. If you
- * allocate something here, you are expected to clean it up when
- * appropriate.
- */
-MemoryContext TopMemoryContext = (MemoryContext) &TopGlobalMemoryData;
-
-
-
-
-/*
- * Module State
- */
-
-/*
- * EnableMemoryContext
- * Enables/disables memory management and global contexts.
+ * This must be called before creating contexts or allocating memory in
+ * contexts. TopMemoryContext and ErrorContext are initialized here;
+ * other contexts must be created afterwards.
*
- * Note:
- * This must be called before creating contexts or allocating memory.
- * This must be called before other contexts are created.
+ * In normal multi-backend operation, this is called once during
+ * postmaster startup, and not at all by individual backend startup
+ * (since the backends inherit an already-initialized context subsystem
+ * by virtue of being forked off the postmaster).
*
- * Exceptions:
- * BadArg if on is invalid.
- * BadState if on is false when disabled.
+ * In a standalone backend this must be called during backend startup.
*/
void
-EnableMemoryContext(bool on)
+MemoryContextInit(void)
{
- static bool processing = false;
-
- AssertState(!processing);
- AssertArg(BoolIsValid(on));
-
- if (BypassEnable(&MemoryContextEnableCount, on))
- return;
-
- processing = true;
-
- if (on)
- { /* initialize */
- /* initialize TopGlobalMemoryData.setData */
- AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
- (Size) 0);
-
- /* make TopGlobalMemoryData member of ActiveGlobalMemorySet */
- OrderedSetInit(ActiveGlobalMemorySet,
- offsetof(struct GlobalMemoryData, elemData));
- OrderedElemPushInto(&TopGlobalMemoryData.elemData,
- ActiveGlobalMemorySet);
-
- /* initialize CurrentMemoryContext */
- CurrentMemoryContext = TopMemoryContext;
-
- }
- else
- { /* cleanup */
- GlobalMemory context;
-
- /* walk the list of allocations */
- while (PointerIsValid(context = (GlobalMemory)
- OrderedSetGetHead(ActiveGlobalMemorySet)))
- {
-
- if (context == &TopGlobalMemoryData)
- {
- /* don't free it and clean it last */
- OrderedElemPop(&TopGlobalMemoryData.elemData);
- }
- else
- GlobalMemoryDestroy(context);
- /* what is needed for the top? */
- }
-
- /*
- * Freeing memory here should be safe as this is called only after
- * all modules which allocate in TopMemoryContext have been
- * disabled.
- */
-
- /* step through remaining allocations and log */
- /* AllocSetStep(...); */
-
- /* deallocate whatever is left */
- AllocSetReset(&TopGlobalMemoryData.setData);
- }
-
- processing = false;
+ AssertState(TopMemoryContext == NULL);
+ /*
+ * Initialize TopMemoryContext as an AllocSetContext with slow
+ * growth rate --- we don't really expect much to be allocated in it.
+ *
+ * (There is special-case code in MemoryContextCreate() for this call.)
+ */
+ TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
+ "TopMemoryContext",
+ 8 * 1024,
+ 8 * 1024,
+ 8 * 1024);
+ /*
+ * Not having any other place to point CurrentMemoryContext,
+ * make it point to TopMemoryContext. Caller should change this soon!
+ */
+ CurrentMemoryContext = TopMemoryContext;
+ /*
+ * Initialize ErrorContext as an AllocSetContext with slow
+ * growth rate --- we don't really expect much to be allocated in it.
+ * More to the point, require it to contain at least 8K at all times.
+ * This is the only case where retained memory in a context is
+ * *essential* --- we want to be sure ErrorContext still has some
+ * memory even if we've run out elsewhere!
+ */
+ ErrorContext = AllocSetContextCreate(TopMemoryContext,
+ "ErrorContext",
+ 8 * 1024,
+ 8 * 1024,
+ 8 * 1024);
}
/*
- * MemoryContextAlloc
- * Returns pointer to aligned allocated memory in the given context.
- *
- * Note:
- * none
+ * MemoryContextReset
+ * Release all space allocated within a context and its descendants,
+ * but don't delete the contexts themselves.
*
- * Exceptions:
- * BadState if called before InitMemoryManager.
- * BadArg if context is invalid or if size is 0.
- * BadAllocSize if size is larger than MaxAllocSize.
+ * The type-specific reset routine handles the context itself, but we
+ * have to do the recursion for the children.
*/
-Pointer
-MemoryContextAlloc(MemoryContext context, Size size)
+void
+MemoryContextReset(MemoryContext context)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
-
- LogTrap(!AllocSizeIsValid(size), BadAllocSize,
- ("size=%d [0x%x]", size, size));
-
- return context->method->alloc(context, size);
+ MemoryContextResetChildren(context);
+ (*context->methods->reset) (context);
}
/*
- * MemoryContextFree
- * Frees allocated memory referenced by pointer in the given context.
- *
- * Note:
- * none
- *
- * Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * MemoryContextResetChildren
+ * Release all space allocated within a context's descendants,
+ * but don't delete the contexts themselves. The named context
+ * itself is not touched.
*/
void
-MemoryContextFree(MemoryContext context, Pointer pointer)
+MemoryContextResetChildren(MemoryContext context)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
- AssertArg(PointerIsValid(pointer));
+ MemoryContext child;
- context->method->free_p(context, pointer);
+ for (child = context->firstchild; child != NULL; child = child->nextchild)
+ {
+ MemoryContextReset(child);
+ }
}
/*
- * MemoryContextRelloc
- * Returns pointer to aligned allocated memory in the given context.
+ * MemoryContextDelete
+ * Delete a context and its descendants, and release all space
+ * allocated therein.
*
- * Note:
- * none
- *
- * Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * The type-specific delete routine removes all subsidiary storage
+ * for the context, but we have to delete the context node itself,
+ * as well as recurse to get the children. We must also delink the
+ * node from its parent, if it has one.
*/
-Pointer
-MemoryContextRealloc(MemoryContext context,
- Pointer pointer,
- Size size)
+void
+MemoryContextDelete(MemoryContext context)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
- AssertArg(PointerIsValid(pointer));
+ /* We had better not be deleting TopMemoryContext ... */
+ Assert(context != TopMemoryContext);
+ /* And not CurrentMemoryContext, either */
+ Assert(context != CurrentMemoryContext);
+
+ MemoryContextDeleteChildren(context);
+ /*
+ * We delink the context from its parent before deleting it,
+ * so that if there's an error we won't have deleted/busted
+ * contexts still attached to the context tree. Better a leak
+ * than a crash.
+ */
+ if (context->parent)
+ {
+ MemoryContext parent = context->parent;
- LogTrap(!AllocSizeIsValid(size), BadAllocSize,
- ("size=%d [0x%x]", size, size));
+ if (context == parent->firstchild)
+ {
+ parent->firstchild = context->nextchild;
+ }
+ else
+ {
+ MemoryContext child;
- return context->method->realloc(context, pointer, size);
+ for (child = parent->firstchild; child; child = child->nextchild)
+ {
+ if (context == child->nextchild)
+ {
+ child->nextchild = context->nextchild;
+ break;
+ }
+ }
+ }
+ }
+ (*context->methods->delete) (context);
+ pfree(context);
}
/*
- * MemoryContextGetName
- * Returns pointer to aligned allocated memory in the given context.
- *
- * Note:
- * none
- *
- * Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * MemoryContextDeleteChildren
+ * Delete all the descendants of the named context and release all
+ * space allocated therein. The named context itself is not touched.
*/
-#ifdef NOT_USED
-char *
-MemoryContextGetName(MemoryContext context)
+void
+MemoryContextDeleteChildren(MemoryContext context)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
-
- return context->method->getName(context);
+ /*
+ * MemoryContextDelete will delink the child from me,
+ * so just iterate as long as there is a child.
+ */
+ while (context->firstchild != NULL)
+ {
+ MemoryContextDelete(context->firstchild);
+ }
}
-#endif
-
/*
- * PointerGetAllocSize
- * Returns size of aligned allocated memory given pointer to it.
+ * MemoryContextResetAndDeleteChildren
+ * Release all space allocated within a context and delete all
+ * its descendants.
*
- * Note:
- * none
- *
- * Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * This is a common combination case where we want to preserve the
+ * specific context but get rid of absolutely everything under it.
*/
-#ifdef NOT_USED
-Size
-PointerGetAllocSize(Pointer pointer)
+void
+MemoryContextResetAndDeleteChildren(MemoryContext context)
{
- AssertState(MemoryContextEnabled);
- AssertArg(PointerIsValid(pointer));
-
- return PSIZE(pointer);
+ MemoryContextDeleteChildren(context);
+ (*context->methods->reset) (context);
}
-#endif
-
/*
- * MemoryContextSwitchTo
- * Returns the current context; installs the given context.
+ * MemoryContextStats
+ * Print statistics about the named context and all its descendants.
*
- * Note:
- * none
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
+ * This is just a debugging utility, so it's not fancy. The statistics
+ * are merely sent to stderr.
*/
-MemoryContext
-MemoryContextSwitchTo(MemoryContext context)
+void
+MemoryContextStats(MemoryContext context)
{
- MemoryContext old;
+ MemoryContext child;
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
-
- old = CurrentMemoryContext;
- CurrentMemoryContext = context;
- return old;
+ (*context->methods->stats) (context);
+ for (child = context->firstchild; child != NULL; child = child->nextchild)
+ {
+ MemoryContextStats(child);
+ }
}
/*
- * External Functions
- */
-/*
- * CreateGlobalMemory
- * Returns new global memory context.
- *
- * Note:
- * Assumes name is static.
+ * MemoryContextContains
+ * Detect whether an allocated chunk of memory belongs to a given
+ * context or not.
*
- * Exceptions:
- * BadState if called when disabled.
- * BadState if called outside TopMemoryContext (TopGlobalMemory).
- * BadArg if name is invalid.
+ * Caution: this test is reliable as long as 'pointer' does point to
+ * a chunk of memory allocated from *some* context. If 'pointer' points
+ * at memory obtained in some other way, there is a small chance of a
+ * false-positive result, since the bits right before it might look like
+ * a valid chunk header by chance.
*/
-GlobalMemory
-CreateGlobalMemory(char *name) /* XXX MemoryContextName */
+bool
+MemoryContextContains(MemoryContext context, void *pointer)
{
- GlobalMemory context;
- MemoryContext savecxt;
-
- AssertState(MemoryContextEnabled);
-
- savecxt = MemoryContextSwitchTo(TopMemoryContext);
-
- context = (GlobalMemory) newNode(sizeof(struct GlobalMemoryData), T_GlobalMemory);
- context->method = &GlobalContextMethodsData;
- context->name = name; /* assumes name is static */
- AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0);
-
- /* link the context */
- OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet);
-
- MemoryContextSwitchTo(savecxt);
- return context;
+ StandardChunkHeader *header;
+
+ /*
+ * Try to detect bogus pointers handed to us, poorly though we can.
+ * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+ * an allocated chunk.
+ */
+ if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
+ return false;
+ /*
+ * OK, it's probably safe to look at the chunk header.
+ */
+ header = (StandardChunkHeader *)
+ ((char *) pointer - STANDARDCHUNKHEADERSIZE);
+ /*
+ * If the context link doesn't match then we certainly have a
+ * non-member chunk. Also check for a reasonable-looking size
+ * as extra guard against being fooled by bogus pointers.
+ */
+ if (header->context == context && AllocSizeIsValid(header->size))
+ return true;
+ return false;
}
-/*
- * GlobalMemoryDestroy
- * Destroys given global memory context.
+/*--------------------
+ * MemoryContextCreate
+ * Context-type-independent part of context creation.
+ *
+ * This is only intended to be called by context-type-specific
+ * context creation routines, not by the unwashed masses.
+ *
+ * The context creation procedure is a little bit tricky because
+ * we want to be sure that we don't leave the context tree invalid
+ * in case of failure (such as insufficient memory to allocate the
+ * context node itself). The procedure goes like this:
+ * 1. Context-type-specific routine first calls MemoryContextCreate(),
+ * passing the appropriate tag/size/methods values (the methods
+ * pointer will ordinarily point to statically allocated data).
+ * The parent and name parameters usually come from the caller.
+ * 2. MemoryContextCreate() attempts to allocate the context node,
+ * plus space for the name. If this fails we can elog() with no
+ * damage done.
+ * 3. We fill in all of the type-independent MemoryContext fields.
+ * 4. We call the type-specific init routine (using the methods pointer).
+ * The init routine is required to make the node minimally valid
+ * with zero chance of failure --- it can't allocate more memory,
+ * for example.
+ * 5. Now we have a minimally valid node that can behave correctly
+ * when told to reset or delete itself. We link the node to its
+ * parent (if any), making the node part of the context tree.
+ * 6. We return to the context-type-specific routine, which finishes
+ * up type-specific initialization. This routine can now do things
+ * that might fail (like allocate more memory), so long as it's
+ * sure the node is left in a state that delete will handle.
+ *
+ * This protocol doesn't prevent us from leaking memory if step 6 fails
+ * during creation of a top-level context, since there's no parent link
+ * in that case. However, if you run out of memory while you're building
+ * a top-level context, you might as well go home anyway...
*
- * Exceptions:
- * BadState if called when disabled.
- * BadState if called outside TopMemoryContext (TopGlobalMemory).
- * BadArg if context is invalid GlobalMemory.
- * BadArg if context is TopMemoryContext (TopGlobalMemory).
+ * Normally, the context node and the name are allocated from
+ * TopMemoryContext (NOT from the parent context, since the node must
+ * survive resets of its parent context!). However, this routine is itself
+ * used to create TopMemoryContext! If we see that TopMemoryContext is NULL,
+ * we assume we are creating TopMemoryContext and use malloc() to allocate
+ * the node.
+ *
+ * Note that the name field of a MemoryContext does not point to
+ * separately-allocated storage, so it should not be freed at context
+ * deletion.
+ *--------------------
*/
-void
-GlobalMemoryDestroy(GlobalMemory context)
+MemoryContext
+MemoryContextCreate(NodeTag tag, Size size,
+ MemoryContextMethods *methods,
+ MemoryContext parent,
+ const char *name)
{
- AssertState(MemoryContextEnabled);
- AssertArg(IsA(context, GlobalMemory));
- AssertArg(context != &TopGlobalMemoryData);
+ MemoryContext node;
+ Size needed = size + strlen(name) + 1;
- AllocSetReset(&context->setData);
-
- /* unlink and delete the context */
- OrderedElemPop(&context->elemData);
- MemoryContextFree(TopMemoryContext, (Pointer) context);
-}
+ /* Get space for node and name */
+ if (TopMemoryContext != NULL)
+ {
+ /* Normal case: allocate the node in TopMemoryContext */
+ node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
+ needed);
+ }
+ else
+ {
+ /* Special case for startup: use good ol' malloc */
+ node = (MemoryContext) malloc(needed);
+ Assert(node != NULL);
+ }
-/*****************************************************************************
- * PRIVATE *
- *****************************************************************************/
+ /* Initialize the node as best we can */
+ MemSet(node, 0, size);
+ node->type = tag;
+ node->methods = methods;
+ node->parent = NULL; /* for the moment */
+ node->firstchild = NULL;
+ node->nextchild = NULL;
+ node->name = ((char *) node) + size;
+ strcpy(node->name, name);
+
+ /* Type-specific routine finishes any other essential initialization */
+ (*node->methods->init) (node);
+
+ /* OK to link node to parent (if any) */
+ if (parent)
+ {
+ node->parent = parent;
+ node->nextchild = parent->firstchild;
+ parent->firstchild = node;
+ }
-/*
- * GlobalMemoryAlloc
- * Returns pointer to aligned space in the global context.
- *
- * Exceptions:
- * ExhaustedMemory if allocation fails.
- */
-static Pointer
-GlobalMemoryAlloc(GlobalMemory this, Size size)
-{
- return AllocSetAlloc(&this->setData, size);
+ /* Return to type-specific creation routine to finish up */
+ return node;
}
/*
- * GlobalMemoryFree
- * Frees allocated memory in the global context.
+ * MemoryContextAlloc
+ * Allocate space within the specified context.
*
- * Exceptions:
- * BadContextErr if current context is not the global context.
- * BadArgumentsErr if pointer is invalid.
+ * This could be turned into a macro, but we'd have to import
+ * nodes/memnodes.h into postgres.h which seems a bad idea.
*/
-static void
-GlobalMemoryFree(GlobalMemory this,
- Pointer pointer)
+void *
+MemoryContextAlloc(MemoryContext context, Size size)
{
- AllocSetFree(&this->setData, pointer);
-}
+ AssertArg(MemoryContextIsValid(context));
-/*
- * GlobalMemoryRealloc
- * Returns pointer to aligned space in the global context.
- *
- * Note:
- * Memory associated with the pointer is freed before return.
- *
- * Exceptions:
- * BadContextErr if current context is not the global context.
- * BadArgumentsErr if pointer is invalid.
- * NoMoreMemoryErr if allocation fails.
- */
-static Pointer
-GlobalMemoryRealloc(GlobalMemory this,
- Pointer pointer,
- Size size)
-{
- return AllocSetRealloc(&this->setData, pointer, size);
+ LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+ ("size=%d [0x%x]", size, size));
+
+ return (*context->methods->alloc) (context, size);
}
/*
- * GlobalMemoryGetName
- * Returns name string for context.
- *
- * Exceptions:
- * ???
+ * pfree
+ * Release an allocated chunk.
*/
-static char *
-GlobalMemoryGetName(GlobalMemory this)
+void
+pfree(void *pointer)
{
- return this->name;
+ StandardChunkHeader *header;
+
+ /*
+ * Try to detect bogus pointers handed to us, poorly though we can.
+ * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+ * an allocated chunk.
+ */
+ Assert(pointer != NULL);
+ Assert(pointer == (void *) MAXALIGN(pointer));
+ /*
+ * OK, it's probably safe to look at the chunk header.
+ */
+ header = (StandardChunkHeader *)
+ ((char *) pointer - STANDARDCHUNKHEADERSIZE);
+
+ AssertArg(MemoryContextIsValid(header->context));
+
+ (*header->context->methods->free_p) (header->context, pointer);
}
/*
- * GlobalMemoryDump
- * Dumps global memory context for debugging.
+ * repalloc
*
- * Exceptions:
- * ???
*/
-static void
-GlobalMemoryDump(GlobalMemory this)
+void *
+repalloc(void *pointer, Size size)
{
- GlobalMemory context;
-
- printf("--\n%s:\n", GlobalMemoryGetName(this));
+ StandardChunkHeader *header;
+
+ /*
+ * Try to detect bogus pointers handed to us, poorly though we can.
+ * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+ * an allocated chunk.
+ */
+ Assert(pointer != NULL);
+ Assert(pointer == (void *) MAXALIGN(pointer));
+ /*
+ * OK, it's probably safe to look at the chunk header.
+ */
+ header = (StandardChunkHeader *)
+ ((char *) pointer - STANDARDCHUNKHEADERSIZE);
+
+ AssertArg(MemoryContextIsValid(header->context));
- context = (GlobalMemory) OrderedElemGetPredecessor(&this->elemData);
- if (PointerIsValid(context))
- printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
-
- context = (GlobalMemory) OrderedElemGetSuccessor(&this->elemData);
- if (PointerIsValid(context))
- printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
+ LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+ ("size=%d [0x%x]", size, size));
- AllocSetDump(&this->setData);
+ return (*header->context->methods->realloc) (header->context,
+ pointer, size);
}
/*
- * DumpGlobalMemories
- * Dumps all global memory contexts for debugging.
- *
- * Exceptions:
- * ???
+ * MemoryContextSwitchTo
+ * Returns the current context; installs the given context.
*/
-#ifdef NOT_USED
-static void
-DumpGlobalMemories()
+MemoryContext
+MemoryContextSwitchTo(MemoryContext context)
{
- GlobalMemory context;
-
- context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
+ MemoryContext old;
- while (PointerIsValid(context))
- {
- GlobalMemoryDump(context);
+ AssertArg(MemoryContextIsValid(context));
- context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
- }
+ old = CurrentMemoryContext;
+ CurrentMemoryContext = context;
+ return old;
}
-#endif
-
/*
- * GlobalMemoryStats
- * Displays stats about memory consumption of all global contexts.
+ * MemoryContextStrdup
+ * Like strdup(), but allocate from the specified context
*/
-void
-GlobalMemoryStats(void)
+char *
+MemoryContextStrdup(MemoryContext context, const char *string)
{
- GlobalMemory context;
+ char *nstr;
+ Size len = strlen(string) + 1;
- context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
+ nstr = (char *) MemoryContextAlloc(context, len);
- while (PointerIsValid(context))
- {
- AllocSetStats(&context->setData, GlobalMemoryGetName(context));
- context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
- }
+ memcpy(nstr, string, len);
+
+ return nstr;
}
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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;
-}
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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;
-}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.36 2000/04/12 17:16:10 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.37 2000/06/28 03:32:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*
* struct PortalD {
* char* name;
- * classObj(PortalVariableMemory) variable;
- * classObj(PortalHeapMemory) heap;
+ * classObj(MemoryContext) heap;
* List queryDesc;
* EState state;
* void (*cleanup) ARGS((Portal portal));
* };
*
* I hope this makes things clearer to whoever reads this -cim 2/22/91
- *
- * Here is an old comment taken from nodes/memnodes.h
- *
- * MemoryContext
- * A logical context in which memory allocations occur.
- *
- * The types of memory contexts can be thought of as members of the
- * following inheritance hierarchy with properties summarized below.
- *
- * Node
- * |
- * MemoryContext___
- * / \
- * GlobalMemory PortalMemoryContext
- * / \
- * PortalVariableMemory PortalHeapMemory
- *
- * Flushed at Flushed at Checkpoints
- * Transaction Portal
- * Commit Close
- *
- * GlobalMemory n n n
- * PortalVariableMemory n y n
- * PortalHeapMemory y y y *
- *
*/
#include "postgres.h"
#include "lib/hasht.h"
-#include "utils/module.h"
+#include "utils/memutils.h"
#include "utils/portal.h"
static void CollectNamedPortals(Portal *portalP, int destroy);
-static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
-static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
-static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
-
-/* ----------------
- * ALLOCFREE_ERROR_ABORT
- * define this if you want a core dump when you try to
- * free memory already freed -cim 2/9/91
- * ----------------
- */
-#undef ALLOCFREE_ERROR_ABORT
/* ----------------
* Global state
* ----------------
*/
-static int PortalManagerEnableCount = 0;
-
#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
typedef struct portalhashent
Portal portal;
} PortalHashEnt;
-#define PortalManagerEnabled (PortalManagerEnableCount >= 1)
-
static HTAB *PortalHashTable = NULL;
#define PortalHashTableLookup(NAME, PORTAL) \
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
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)
CollectNamedPortals(NULL, 1);
}
-/* ----------------
- * PortalDump
- * ----------------
- */
-#ifdef NOT_USED
-static void
-PortalDump(Portal *thisP, int dummy)
-{
- /* XXX state/argument checking here */
-
- PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
- PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
-}
-
-#endif
-
-/* ----------------
- * DumpPortals
- * ----------------
- */
-#ifdef NOT_USED
-static void
-DumpPortals()
-{
- /* XXX state checking here */
-
- HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0);
-}
-
-#endif
-
/* ----------------------------------------------------------------
* public portal interface functions
* ----------------------------------------------------------------
*/
/*
* EnablePortalManager
- * Enables/disables the portal management module.
+ * Enables the portal management module at backend startup.
*/
void
-EnablePortalManager(bool on)
+EnablePortalManager(void)
{
- static bool processing = false;
HASHCTL ctl;
- AssertState(!processing);
- AssertArg(BoolIsValid(on));
-
- if (BypassEnable(&PortalManagerEnableCount, on))
- return;
-
- processing = true;
-
- if (on)
- { /* initialize */
- EnableMemoryContext(true);
-
- PortalMemory = CreateGlobalMemory(PortalMemoryName);
-
- ctl.keysize = MAX_PORTALNAME_LEN;
- ctl.datasize = sizeof(Portal);
-
- /*
- * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
- * how many hash table entries to create, initially
- */
- PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
-
- CreateNewBlankPortal();
-
- }
- else
- { /* cleanup */
- if (PortalIsValid(BlankPortal))
- {
- PortalDrop(&BlankPortal);
- MemoryContextFree((MemoryContext) PortalMemory,
- (Pointer) BlankPortal);
- BlankPortal = NULL;
- }
-
- /*
- * Each portal must free its non-memory resources specially.
- */
- HashTableWalk(PortalHashTable, (HashtFunc) PortalDrop, 0);
- hash_destroy(PortalHashTable);
- PortalHashTable = NULL;
+ Assert(PortalMemory == NULL);
- GlobalMemoryDestroy(PortalMemory);
- PortalMemory = NULL;
+ PortalMemory = AllocSetContextCreate(TopMemoryContext,
+ "PortalMemory",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
- EnableMemoryContext(true);
- }
+ ctl.keysize = MAX_PORTALNAME_LEN;
+ ctl.datasize = sizeof(Portal);
- processing = false;
+ /*
+ * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
+ * how many hash table entries to create, initially
+ */
+ PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
}
/*
* GetPortalByName
- * Returns a portal given a portal name; returns blank portal given
- * NULL; returns invalid portal if portal not found.
- *
- * Exceptions:
- * BadState if called when disabled.
+ * Returns a portal given a portal name, or NULL if name not found.
*/
Portal
GetPortalByName(char *name)
{
Portal portal;
- AssertState(PortalManagerEnabled);
-
if (PointerIsValid(name))
PortalHashTableLookup(name, portal);
else
- {
- if (!PortalIsValid(BlankPortal))
- CreateNewBlankPortal();
- portal = BlankPortal;
- }
-
- return portal;
-}
-
-/*
- * BlankPortalAssignName
- * Returns former blank portal as portal with given name.
- *
- * Side effect:
- * All references to the former blank portal become incorrect.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadState if called without an intervening call to GetPortalByName(NULL).
- * BadArg if portal name is invalid.
- * "WARN" if portal name is in use.
- */
-Portal
-BlankPortalAssignName(char *name) /* XXX PortalName */
-{
- Portal portal;
- uint16 length;
-
- AssertState(PortalManagerEnabled);
- AssertState(PortalIsValid(BlankPortal));
- AssertArg(PointerIsValid(name)); /* XXX PortalName */
-
- portal = GetPortalByName(name);
- if (PortalIsValid(portal))
- {
- elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
- return portal;
- }
-
- /*
- * remove blank portal
- */
- portal = BlankPortal;
- BlankPortal = NULL;
-
- /*
- * initialize portal name
- */
- length = 1 + strlen(name);
- portal->name = (char *)
- MemoryContextAlloc((MemoryContext) &portal->variable, length);
-
- strncpy(portal->name, name, length);
-
- /*
- * put portal in table
- */
- PortalHashTableInsert(portal);
+ portal = NULL;
return portal;
}
EState *state,
void (*cleanup) (Portal portal))
{
- AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
AssertArg(IsA((Node *) state, EState));
QueryDesc *
PortalGetQueryDesc(Portal portal)
{
- AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
return portal->queryDesc;
EState *
PortalGetState(Portal portal)
{
- AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
return portal->state;
* CreatePortal
* Returns a new portal given a name.
*
- * Note:
- * This is expected to be of very limited usability. See instead,
- * BlankPortalAssignName.
- *
* Exceptions:
* BadState if called when disabled.
* BadArg if portal name is invalid.
- * "WARN" if portal name is in use.
+ * "NOTICE" if portal name is in use (existing portal is returned!)
*/
Portal
-CreatePortal(char *name) /* XXX PortalName */
+CreatePortal(char *name)
{
Portal portal;
- uint16 length;
- AssertState(PortalManagerEnabled);
- AssertArg(PointerIsValid(name)); /* XXX PortalName */
+ AssertArg(PointerIsValid(name));
portal = GetPortalByName(name);
if (PortalIsValid(portal))
{
- elog(NOTICE, "CreatePortal: portal %s already exists", name);
+ elog(NOTICE, "CreatePortal: portal \"%s\" already exists", name);
return portal;
}
/* make new portal structure */
- portal = (Portal)
- MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
+ portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
- /* initialize portal variable context */
- NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
- AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
- portal->variable.method = &PortalVariableContextMethodsData;
+ /* initialize portal name */
+ portal->name = MemoryContextStrdup(PortalMemory, name);
/* initialize portal heap context */
- NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
- portal->heap.block = NULL;
- FixedStackInit(&portal->heap.stackData,
- offsetof(HeapMemoryBlockData, itemData));
- portal->heap.method = &PortalHeapContextMethodsData;
-
- /* initialize portal name */
- length = 1 + strlen(name);
- portal->name = (char *)
- MemoryContextAlloc((MemoryContext) &portal->variable, length);
- strncpy(portal->name, name, length);
+ portal->heap = AllocSetContextCreate(PortalMemory,
+ "PortalHeapMemory",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
/* initialize portal query */
portal->queryDesc = NULL;
portal->attinfo = NULL;
portal->state = NULL;
+
portal->cleanup = NULL;
/* put portal in table */
PortalHashTableInsert(portal);
- /* Trap(PointerIsValid(name), Unimplemented); */
return portal;
}
{
Portal portal = *portalP;
- AssertState(PortalManagerEnabled);
AssertArg(PortalIsValid(portal));
- /* remove portal from table if not blank portal */
- if (portal != BlankPortal)
- PortalHashTableDelete(portal);
+ /* remove portal from hash table */
+ PortalHashTableDelete(portal);
/* reset portal */
if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal);
- PortalResetHeapMemory(portal);
- MemoryContextFree((MemoryContext) &portal->variable,
- (Pointer) portal->name);
- AllocSetReset(&portal->variable.setData); /* XXX log */
-
- /*
- * In the case of a transaction abort it is possible that we get
- * called while one of the memory contexts of the portal we're
- * destroying is the current memory context.
- *
- * Don't know how to handle that cleanly because it is required to be in
- * that context right now. This portal struct remains allocated in the
- * PortalMemory context until backend dies.
- *
- * Not happy with that, but it's better to loose some bytes of memory
- * than to have the backend dump core.
- *
- * --- Feb. 04, 1999 Jan Wieck
- */
- if (CurrentMemoryContext == (MemoryContext) PortalGetHeapMemory(portal))
- return;
- if (CurrentMemoryContext == (MemoryContext) PortalGetVariableMemory(portal))
- return;
-
- if (portal != BlankPortal)
- MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
-}
-
-/* ----------------
- * PortalResetHeapMemory
- * Resets portal's heap memory context.
- *
- * Someday, Reset, Start, and End can be optimized by keeping a global
- * portal module stack of free HeapMemoryBlock's. This will make Start
- * and End be fast.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadState if called when not in PortalHeapMemory context.
- * BadArg if mode is invalid.
- * ----------------
- */
-void
-PortalResetHeapMemory(Portal portal)
-{
- PortalHeapMemory context;
- MemoryContext currentContext;
-
- context = PortalGetHeapMemory(portal);
-
- if (PointerIsValid(context->block))
- {
- /* save present context */
- currentContext = MemoryContextSwitchTo((MemoryContext) context);
-
- do
- {
- EndPortalAllocMode();
- } while (PointerIsValid(context->block));
-
- /* restore context */
- MemoryContextSwitchTo(currentContext);
- }
-}
-
-/*
- * StartPortalAllocMode
- * Starts a new block of portal heap allocation using mode and limit;
- * the current block is disabled until EndPortalAllocMode is called.
- *
- * Note:
- * Note blocks may be stacked and restored arbitarily.
- * The semantics of mode and limit are described in aset.h.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadState if called when not in PortalHeapMemory context.
- * BadArg if mode is invalid.
- */
-void
-StartPortalAllocMode(AllocMode mode, Size limit)
-{
- PortalHeapMemory context;
-
- AssertState(PortalManagerEnabled);
- AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
- /* AssertArg(AllocModeIsValid); */
-
- context = (PortalHeapMemory) CurrentMemoryContext;
-
- /* stack current mode */
- if (PointerIsValid(context->block))
- FixedStackPush(&context->stackData, context->block);
-
- /* allocate and initialize new block */
- context->block = MemoryContextAlloc(
- (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
- sizeof(HeapMemoryBlockData));
-
- /* XXX careful, context->block has never been stacked => bad state */
-
- AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
-}
-
-/*
- * EndPortalAllocMode
- * Ends current block of portal heap allocation; previous block is
- * reenabled.
- *
- * Note:
- * Note blocks may be stacked and restored arbitarily.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadState if called when not in PortalHeapMemory context.
- */
-void
-EndPortalAllocMode()
-{
- PortalHeapMemory context;
+ /* release subsidiary storage */
+ MemoryContextDelete(PortalGetHeapMemory(portal));
- AssertState(PortalManagerEnabled);
- AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
-
- context = (PortalHeapMemory) CurrentMemoryContext;
- AssertState(PointerIsValid(context->block)); /* XXX Trap(...) */
-
- /* free current mode */
- AllocSetReset(&HEAPMEMBLOCK(context)->setData);
- MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
- context->block);
-
- /* restore previous mode */
- context->block = FixedStackPop(&context->stackData);
-}
-
-/*
- * PortalGetVariableMemory
- * Returns variable memory context for a given portal.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
- */
-PortalVariableMemory
-PortalGetVariableMemory(Portal portal)
-{
- return &portal->variable;
+ /* release name and portal data (both are in PortalMemory) */
+ pfree(portal->name);
+ pfree(portal);
}
/*
* PortalGetHeapMemory
* Returns heap memory context for a given portal.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
*/
-PortalHeapMemory
+MemoryContext
PortalGetHeapMemory(Portal portal)
{
- return &portal->heap;
-}
-
-/*
- * PortalVariableMemoryGetPortal
- * Returns portal containing given variable memory context.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
- */
-static Portal
-PortalVariableMemoryGetPortal(PortalVariableMemory context)
-{
- return (Portal) ((char *) context - offsetof(PortalD, variable));
-}
-
-/*
- * PortalHeapMemoryGetPortal
- * Returns portal containing given heap memory context.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
- */
-static Portal
-PortalHeapMemoryGetPortal(PortalHeapMemory context)
-{
- return (Portal) ((char *) context - offsetof(PortalD, heap));
-}
-
-/*
- * PortalVariableMemoryGetHeapMemory
- * Returns heap memory context associated with given variable memory.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
- */
-#ifdef NOT_USED
-PortalHeapMemory
-PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
-{
- return ((PortalHeapMemory) ((char *) context
- - offsetof(PortalD, variable)
- +offsetof(PortalD, heap)));
-}
-
-#endif
-
-/*
- * PortalHeapMemoryGetVariableMemory
- * Returns variable memory context associated with given heap memory.
- *
- * Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
- */
-static PortalVariableMemory
-PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
-{
- return ((PortalVariableMemory) ((char *) context
- - offsetof(PortalD, heap)
- +offsetof(PortalD, variable)));
+ return portal->heap;
}
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "utils/portal.h"
-extern MemoryContext PortalExecutorHeapMemory;
/*
* PerformPortalFetch
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: hashjoin.h,v 1.16 2000/01/26 05:58:05 momjian Exp $
+ * $Id: hashjoin.h,v 1.17 2000/06/28 03:33:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*
* Each active hashjoin has a HashJoinTable control block which is
* palloc'd in the executor's context. All other storage needed for
- * the hashjoin is kept in a private "named portal", one for each hashjoin.
+ * the hashjoin is kept in private memory contexts, two for each hashjoin.
* This makes it easy and fast to release the storage when we don't need it
* anymore.
*
- * The portal manager guarantees that portals will be discarded at end of
- * transaction, so we have no problem with a memory leak if the join is
+ * The contexts are made children of TransactionCommandContext, ensuring
+ * that they will be discarded at end of statement even if the join is
* aborted early by an error. (Likewise, any temporary files we make will
* be cleaned up by the virtual file manager in event of an error.)
*
* Storage that should live through the entire join is allocated from the
- * portal's "variable context", while storage that is only wanted for the
- * current batch is allocated in the portal's "heap context". By popping
- * the portal's heap at the end of a batch, we free all the per-batch storage
- * reliably and without tedium.
+ * "hashCxt", while storage that is only wanted for the current batch is
+ * allocated in the "batchCxt". By resetting the batchCxt at the end of
+ * each batch, we free all the per-batch storage reliably and without tedium.
* ----------------------------------------------------------------
*/
* 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;
#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"
extern void SPI_pfree(void *pointer);
extern void SPI_freetuple(HeapTuple pointer);
+extern void AtEOXact_SPI(void);
+
#endif /* SPI_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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 */
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqsignal.h,v 1.13 2000/06/15 00:52:11 momjian Exp $
+ * $Id: pqsignal.h,v 1.14 2000/06/28 03:33:14 tgl Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
extern sigset_t UnBlockSig,
BlockSig;
-#define PG_INITMASK() ( \
- sigemptyset(&UnBlockSig), \
- sigfillset(&BlockSig) \
- )
#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)
#else
extern int UnBlockSig,
BlockSig;
-#define PG_INITMASK() ( \
- UnBlockSig = 0, \
- BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) | \
- sigmask(SIGTERM) | sigmask(SIGALRM) | \
- sigmask(SIGINT) | sigmask(SIGUSR1) | \
- sigmask(SIGUSR2) | sigmask(SIGCHLD) | \
- sigmask(SIGWINCH) | sigmask(SIGFPE) \
- )
#define PG_SETMASK(mask) sigsetmask(*((int*)(mask)))
#endif
typedef void (*pqsigfunc) (int);
+extern void pqinitmask(void);
+
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
#endif /* PQSIGNAL_H */
* 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
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 */
/* 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)
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: memnodes.h,v 1.16 2000/01/26 05:58:16 momjian Exp $
+ * $Id: memnodes.h,v 1.17 2000/06/28 03:33:15 tgl Exp $
*
- * XXX the typedefs in this file are different from the other ???nodes.h;
- * they are pointers to structures instead of the structures themselves.
- * If you're wondering, this is plain laziness. I don't want to touch
- * the memory context code which should be revamped altogether some day.
- * - ay 10/94
*-------------------------------------------------------------------------
*/
#ifndef MEMNODES_H
#define MEMNODES_H
-#include "lib/fstack.h"
#include "nodes/nodes.h"
-#include "utils/memutils.h"
/*
* MemoryContext
* A logical context in which memory allocations occur.
*
- * The types of memory contexts can be thought of as members of the
- * following inheritance hierarchy with properties summarized below.
+ * MemoryContext itself is an abstract type that can have multiple
+ * implementations, though for now we have only AllocSetContext.
+ * The function pointers in MemoryContextMethods define one specific
+ * implementation of MemoryContext --- they are a virtual function table
+ * in C++ terms.
*
- * Node
- * |
- * MemoryContext___
- * / \
- * GlobalMemory PortalMemoryContext
- * / \
- * PortalVariableMemory PortalHeapMemory
+ * Node types that are actual implementations of memory contexts must
+ * begin with the same fields as MemoryContext.
*
- * Flushed at Flushed at Checkpoints
- * Transaction Portal
- * Commit Close
- *
- * GlobalMemory n n n
- * PortalVariableMemory n y n
- * PortalHeapMemory y y y
+ * Note: for largely historical reasons, typedef MemoryContext is a pointer
+ * to the context struct rather than the struct type itself.
*/
-typedef struct MemoryContextMethodsData
+typedef struct MemoryContextMethods
{
- Pointer (*alloc) ();
- void (*free_p) (); /* need to use free as a #define, so can't
- * use free */
- Pointer (*realloc) ();
- char *(*getName) ();
- void (*dump) ();
-} *MemoryContextMethods;
+ void *(*alloc) (MemoryContext context, Size size);
+ /* call this free_p in case someone #define's free() */
+ void (*free_p) (MemoryContext context, void *pointer);
+ void *(*realloc) (MemoryContext context, void *pointer, Size size);
+ void (*init) (MemoryContext context);
+ void (*reset) (MemoryContext context);
+ void (*delete) (MemoryContext context);
+ void (*stats) (MemoryContext context);
+} MemoryContextMethods;
+
typedef struct MemoryContextData
{
- NodeTag type;
- MemoryContextMethods method;
+ NodeTag type; /* identifies exact kind of context */
+ MemoryContextMethods *methods; /* virtual function table */
+ MemoryContext parent; /* NULL if no parent (toplevel context) */
+ MemoryContext firstchild; /* head of linked list of children */
+ MemoryContext nextchild; /* next child of same parent */
+ char *name; /* context name (just for debugging) */
} MemoryContextData;
-/* utils/mcxt.h contains typedef struct MemoryContextData *MemoryContext */
+/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */
-/* think about doing this right some time but we'll have explicit fields
- for now -ay 10/94 */
-typedef struct GlobalMemoryData
-{
- NodeTag type;
- MemoryContextMethods method;
- AllocSetData setData;
- char *name;
- OrderedElemData elemData;
-} GlobalMemoryData;
-/* utils/mcxt.h contains typedef struct GlobalMemoryData *GlobalMemory */
-
-typedef struct MemoryContextData *PortalMemoryContext;
+/*
+ * AllocSetContext is our standard implementation of MemoryContext.
+ */
+typedef struct AllocBlockData *AllocBlock; /* internal to aset.c */
+typedef struct AllocChunkData *AllocChunk;
-typedef struct PortalVariableMemoryData
+typedef struct AllocSetContext
{
- NodeTag type;
- MemoryContextMethods method;
- AllocSetData setData;
-} *PortalVariableMemory;
+ MemoryContextData header; /* Standard memory-context fields */
+ /* Info about storage allocated in this context: */
+ AllocBlock blocks; /* head of list of blocks in this set */
+#define ALLOCSET_NUM_FREELISTS 8
+ AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
+ /* Allocation parameters for this context: */
+ Size initBlockSize; /* initial block size */
+ Size maxBlockSize; /* maximum block size */
+ AllocBlock keeper; /* if not NULL, keep this block
+ * over resets */
+} AllocSetContext;
-typedef struct PortalHeapMemoryData
-{
- NodeTag type;
- MemoryContextMethods method;
- Pointer block;
- FixedStackData stackData;
-} *PortalHeapMemory;
/*
* MemoryContextIsValid
* True iff memory context is valid.
+ *
+ * Add new context types to the set accepted by this macro.
*/
#define MemoryContextIsValid(context) \
- (IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \
- IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory))
+ ((context) != NULL && \
+ (IsA((context), AllocSetContext)))
+
#endif /* MEMNODES_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
*---------------------
*/
T_MemoryContext = 400,
- T_GlobalMemory,
- T_PortalMemoryContext,
- T_PortalVariableMemory,
- T_PortalHeapMemory,
+ T_AllocSetContext,
/*---------------------
* TAGS FOR VALUE NODES (pg_list.h)
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "postgres_ext.h"
#include "c.h"
#include "utils/elog.h"
-#include "utils/mcxt.h"
#include "utils/palloc.h"
/* ----------------------------------------------------------------
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pquery.h,v 1.14 2000/01/26 05:58:35 momjian Exp $
+ * $Id: pquery.h,v 1.15 2000/06/28 03:33:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define PQUERY_H
#include "executor/execdesc.h"
+#include "utils/portal.h"
-/* moved to execdesc.h
-extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
- CommandDest dest);
-
-*/
-extern EState *CreateExecutorState(void);
+extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
-extern void ProcessPortal(char *portalName, Query *parseTree,
- Plan *plan, EState *state, TupleDesc attinfo,
- CommandDest dest);
+extern EState *CreateExecutorState(void);
-extern void
- ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
+extern Portal PreparePortal(char *portalName);
-#endif /* pqueryIncluded */
+#endif /* PQUERY_H */
* 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
#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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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
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 */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * mcxt.h
- * POSTGRES memory context definitions.
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: mcxt.h,v 1.17 2000/05/21 02:23:28 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef MCXT_H
-#define MCXT_H
-
-/* These types are declared in nodes/memnodes.h, but most users of memory
- * allocation should just treat them as abstract types, so we do not provide
- * the struct contents here.
- */
-
-typedef struct MemoryContextData *MemoryContext;
-typedef struct GlobalMemoryData *GlobalMemory;
-
-
-extern DLLIMPORT MemoryContext CurrentMemoryContext;
-extern MemoryContext TopMemoryContext;
-
-
-/*
- * MaxAllocSize
- * Arbitrary limit on size of allocations.
- *
- * Note:
- * There is no guarantee that allocations smaller than MaxAllocSize
- * will succeed. Allocation requests larger than MaxAllocSize will
- * be summarily denied.
- *
- * This value should not be referenced except in one place in the code.
- *
- * XXX This should be defined in a file of tunable constants.
- */
-#define MaxAllocSize (0xfffffff) /* 16G - 1 */
-
-/*
- * prototypes for functions in mcxt.c
- */
-extern void EnableMemoryContext(bool on);
-extern Pointer MemoryContextAlloc(MemoryContext context, Size size);
-extern Pointer MemoryContextRealloc(MemoryContext context,
- Pointer pointer,
- Size size);
-extern void MemoryContextFree(MemoryContext context, Pointer pointer);
-extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
-extern GlobalMemory CreateGlobalMemory(char *name);
-extern void GlobalMemoryDestroy(GlobalMemory context);
-extern void GlobalMemoryStats(void);
-
-
-#endif /* MCXT_H */
/*-------------------------------------------------------------------------
*
* memutils.h
- * this file contains general memory alignment, allocation
- * and manipulation stuff that used to be spread out
- * between the following files:
- *
- * align.h alignment macros
- * aset.h memory allocation set stuff
- * oset.h (used by aset.h)
+ * This file contains declarations for memory allocation utility
+ * functions. These are functions that are not quite widely used
+ * enough to justify going in utils/palloc.h, but are still part
+ * of the API of the memory management subsystem.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: memutils.h,v 1.35 2000/05/21 02:23:28 tgl Exp $
+ * $Id: memutils.h,v 1.36 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef MEMUTILS_H
#define MEMUTILS_H
-/* ----------------
- * Alignment macros: align a length or address appropriately for a given type.
- *
- * There used to be some incredibly crufty platform-dependent hackery here,
- * but now we rely on the configure script to get the info for us. Much nicer.
- *
- * NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
- * That case seems extremely unlikely to occur in practice, however.
- * ----------------
- */
+#include "nodes/memnodes.h"
-#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
-
-#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN))
-#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN))
-#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN))
-#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
-#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
-
-/*****************************************************************************
- * oset.h -- Fixed format ordered set definitions. *
- *****************************************************************************/
-/* Note:
- * Fixed format ordered sets are .
- * XXX This is a preliminary version. Work is needed to explain
- * XXX semantics of the external definitions. Otherwise, the
- * XXX functional interface should not change.
- *
- */
-
-typedef struct OrderedElemData OrderedElemData;
-typedef OrderedElemData *OrderedElem;
-typedef struct OrderedSetData OrderedSetData;
-typedef OrderedSetData *OrderedSet;
-
-struct OrderedElemData
-{
- OrderedElem next; /* Next elem or &this->set->dummy */
- OrderedElem prev; /* Previous elem or &this->set->head */
- OrderedSet set; /* Parent set */
-};
-
-struct OrderedSetData
-{
- OrderedElem head; /* First elem or &this->dummy */
- OrderedElem dummy; /* (hack) Terminator == NULL */
- OrderedElem tail; /* Last elem or &this->head */
- Offset offset; /* Offset from struct base to elem */
- /* this could be signed short int! */
-};
-
-extern void OrderedSetInit(OrderedSet set, Offset offset);
-extern Pointer OrderedSetGetHead(OrderedSet set);
-extern Pointer OrderedElemGetPredecessor(OrderedElem elem);
-extern Pointer OrderedElemGetSuccessor(OrderedElem elem);
-extern void OrderedElemPop(OrderedElem elem);
-extern void OrderedElemPushInto(OrderedElem elem, OrderedSet Set);
-
-/*****************************************************************************
- * aset.h -- Allocation set definitions. *
- *****************************************************************************/
/*
- * Description:
- * An allocation set is a set containing allocated elements. When
- * an allocation is requested for a set, memory is allocated and a
- * pointer is returned. Subsequently, this memory may be freed or
- * reallocated. In addition, an allocation set may be reset which
- * will cause all memory allocated within it to be freed.
- *
- * XXX The following material about allocation modes is all OUT OF DATE.
- * aset.c currently implements only one allocation strategy,
- * DynamicAllocMode, and that's the only one anyone ever requests anyway.
- * If we ever did have more strategies, the new ones might or might
- * not look like what is described here...
- *
- * Allocations may occur in four different modes. The mode of
- * allocation does not affect the behavior of allocations except in
- * terms of performance. The allocation mode is set at the time of
- * set initialization. Once the mode is chosen, it cannot be changed
- * unless the set is reinitialized.
- *
- * "Dynamic" mode forces all allocations to occur in a heap. This
- * is a good mode to use when small memory segments are allocated
- * and freed very frequently. This is a good choice when allocation
- * characteristics are unknown. This is the default mode.
- *
- * "Static" mode attempts to allocate space as efficiently as possible
- * without regard to freeing memory. This mode should be chosen only
- * when it is known that many allocations will occur but that very
- * little of the allocated memory will be explicitly freed.
- *
- * "Tunable" mode is a hybrid of dynamic and static modes. The
- * tunable mode will use static mode allocation except when the
- * allocation request exceeds a size limit supplied at the time of set
- * initialization. "Big" objects are allocated using dynamic mode.
- *
- * "Bounded" mode attempts to allocate space efficiently given a limit
- * on space consumed by the allocation set. This restriction can be
- * considered a "soft" restriction, because memory segments will
- * continue to be returned after the limit is exceeded. The limit is
- * specified at the time of set initialization like for tunable mode.
+ * MaxAllocSize
+ * Arbitrary limit on size of allocations.
*
* Note:
- * Allocation sets are not automatically reset on a system reset.
- * Higher level code is responsible for cleaning up.
+ * There is no guarantee that allocations smaller than MaxAllocSize
+ * will succeed. Allocation requests larger than MaxAllocSize will
+ * be summarily denied.
*
- * There may be other modes in the future.
+ * XXX This should be defined in a file of tunable constants.
*/
+#define MaxAllocSize ((Size) 0xfffffff) /* 16G - 1 */
-/*
- * AllocPointer
- * Aligned pointer which may be a member of an allocation set.
- */
-typedef Pointer AllocPointer;
+#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
/*
- * AllocMode
- * Mode of allocation for an allocation set.
- *
- * Note:
- * See above for a description of the various modes.
+ * All chunks allocated by any memory context manager are required to be
+ * preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
+ * A currently-allocated chunk must contain a backpointer to its owning
+ * context as well as the allocated size of the chunk. The backpointer is
+ * used by pfree() and repalloc() to find the context to call. The allocated
+ * size is not absolutely essential, but it's expected to be needed by any
+ * reasonable implementation.
*/
-typedef enum AllocMode
+typedef struct StandardChunkHeader
{
- DynamicAllocMode, /* always dynamically allocate */
- StaticAllocMode, /* always "statically" allocate */
- TunableAllocMode, /* allocations are "tuned" */
- BoundedAllocMode /* allocations bounded to fixed usage */
-} AllocMode;
+ MemoryContext context; /* owning context */
+ Size size; /* size of data space allocated in chunk */
+} StandardChunkHeader;
-#define DefaultAllocMode DynamicAllocMode
+#define STANDARDCHUNKHEADERSIZE MAXALIGN(sizeof(StandardChunkHeader))
-typedef struct AllocSetData *AllocSet;
-typedef struct AllocBlockData *AllocBlock;
-typedef struct AllocChunkData *AllocChunk;
-
-/*
- * AllocSet
- * Allocation set.
- */
-typedef struct AllocSetData
-{
- AllocBlock blocks; /* head of list of blocks in this set */
-#define ALLOCSET_NUM_FREELISTS 8
- AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
- /* Note: this will change in the future to support other modes */
-} AllocSetData;
/*
- * AllocBlock
- * An AllocBlock is the unit of memory that is obtained by aset.c
- * from malloc(). It contains one or more AllocChunks, which are
- * the units requested by palloc() and freed by pfree(). AllocChunks
- * cannot be returned to malloc() individually, instead they are put
- * on freelists by pfree() and re-used by the next palloc() that has
- * a matching request size.
+ * Standard top-level memory contexts.
*
- * AllocBlockData is the header data for a block --- the usable space
- * within the block begins at the next alignment boundary.
+ * Only TopMemoryContext and ErrorContext are initialized by
+ * MemoryContextInit() itself.
*/
-typedef struct AllocBlockData
-{
- AllocSet aset; /* aset that owns this block */
- AllocBlock next; /* next block in aset's blocks list */
- char *freeptr; /* start of free space in this block */
- char *endptr; /* end of space in this block */
-} AllocBlockData;
+extern MemoryContext TopMemoryContext;
+extern MemoryContext ErrorContext;
+extern MemoryContext PostmasterContext;
+extern MemoryContext CacheMemoryContext;
+extern MemoryContext QueryContext;
+extern MemoryContext TopTransactionContext;
+extern MemoryContext TransactionCommandContext;
-/*
- * AllocChunk
- * The prefix of each piece of memory in an AllocBlock
- */
-typedef struct AllocChunkData
-{
- /* aset is the owning aset if allocated, or the freelist link if free */
- void *aset;
- /* size is always the size of the usable space in the chunk */
- Size size;
-} AllocChunkData;
/*
- * AllocPointerIsValid
- * True iff pointer is valid allocation pointer.
+ * Memory-context-type-independent functions in mcxt.c
*/
-#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
+extern void MemoryContextInit(void);
+extern void MemoryContextReset(MemoryContext context);
+extern void MemoryContextDelete(MemoryContext context);
+extern void MemoryContextResetChildren(MemoryContext context);
+extern void MemoryContextDeleteChildren(MemoryContext context);
+extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
+extern void MemoryContextStats(MemoryContext context);
+extern bool MemoryContextContains(MemoryContext context, void *pointer);
/*
- * AllocSetIsValid
- * True iff set is valid allocation set.
+ * This routine handles the context-type-independent part of memory
+ * context creation. It's intended to be called from context-type-
+ * specific creation routines, and noplace else.
*/
-#define AllocSetIsValid(set) PointerIsValid(set)
+extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
+ MemoryContextMethods *methods,
+ MemoryContext parent,
+ const char *name);
-extern void AllocSetInit(AllocSet set, AllocMode mode, Size limit);
-extern void AllocSetReset(AllocSet set);
+/*
+ * Memory-context-type-specific functions
+ */
-extern bool AllocSetContains(AllocSet set, AllocPointer pointer);
-extern AllocPointer AllocSetAlloc(AllocSet set, Size size);
-extern void AllocSetFree(AllocSet set, AllocPointer pointer);
-extern AllocPointer AllocSetRealloc(AllocSet set, AllocPointer pointer,
- Size size);
+/* aset.c */
+extern MemoryContext AllocSetContextCreate(MemoryContext parent,
+ const char *name,
+ Size minContextSize,
+ Size initBlockSize,
+ Size maxBlockSize);
-extern void AllocSetDump(AllocSet set);
-extern void AllocSetStats(AllocSet set, const char *ident);
+/*
+ * Recommended default alloc parameters, suitable for "ordinary" contexts
+ * that might hold quite a lot of data.
+ */
+#define ALLOCSET_DEFAULT_MINSIZE (8 * 1024)
+#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024)
+#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024)
#endif /* MEMUTILS_H */
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * 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 */
* palloc.h
* POSTGRES memory allocator definitions.
*
+ * This file contains the basic memory allocation interface that is
+ * needed by almost every backend module. It is included directly by
+ * postgres.h, so the definitions here are automatically available
+ * everywhere. Keep it lean!
+ *
+ * Memory allocation occurs within "contexts". Every chunk obtained from
+ * palloc()/MemoryContextAlloc() is allocated within a specific context.
+ * The entire contents of a context can be freed easily and quickly by
+ * resetting or deleting the context --- this is both faster and less
+ * prone to memory-leakage bugs than releasing chunks individually.
+ * We organize contexts into context trees to allow fine-grain control
+ * over chunk lifetime while preserving the certainty that we will free
+ * everything that should be freed. See utils/mmgr/README for more info.
+ *
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: palloc.h,v 1.12 2000/01/26 05:58:38 momjian Exp $
+ * $Id: palloc.h,v 1.13 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PALLOC_H
#define PALLOC_H
-#ifdef PALLOC_IS_MALLOC
+/*
+ * Type MemoryContextData is declared in nodes/memnodes.h. Most users
+ * of memory allocation should just treat it as an abstract type, so we
+ * do not provide the struct contents here.
+ */
+typedef struct MemoryContextData *MemoryContext;
+
+/*
+ * CurrentMemoryContext is the default allocation context for palloc().
+ * We declare it here so that palloc() can be a macro. Avoid accessing it
+ * directly! Instead, use MemoryContextSwitchTo() to change the setting.
+ */
+extern DLLIMPORT MemoryContext CurrentMemoryContext;
+
+/*
+ * Fundamental memory-allocation operations (more are in utils/memutils.h)
+ */
+extern void *MemoryContextAlloc(MemoryContext context, Size size);
+
+#define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz))
-#define palloc(s) malloc(s)
-#define pfree(p) free(p)
-#define repalloc(p,s) realloc((p),(s))
+extern void pfree(void *pointer);
-#else /* ! PALLOC_IS_MALLOC */
+extern void *repalloc(void *pointer, Size size);
-/* ----------
- * In the case we use memory contexts, use macro's for palloc() etc.
- * ----------
+extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
+
+/*
+ * These are like standard strdup() except the copied string is
+ * allocated in a context, not with malloc().
+ */
+extern char *MemoryContextStrdup(MemoryContext context, const char *string);
+
+#define pstrdup(str) MemoryContextStrdup(CurrentMemoryContext, (str))
+
+
+/* ----------------
+ * Alignment macros: align a length or address appropriately for a given type.
+ *
+ * There used to be some incredibly crufty platform-dependent hackery here,
+ * but now we rely on the configure script to get the info for us. Much nicer.
+ *
+ * NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
+ * That case seems extremely unlikely to occur in practice, however.
+ * ----------------
*/
-#define palloc(s) ((void *)MemoryContextAlloc(CurrentMemoryContext,(Size)(s)))
-#define pfree(p) MemoryContextFree(CurrentMemoryContext,(Pointer)(p))
-#define repalloc(p,s) ((void *)MemoryContextRealloc(CurrentMemoryContext,(Pointer)(p),(Size)(s)))
-#endif /* PALLOC_IS_MALLOC */
+#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
+
+#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN))
+#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN))
+#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN))
+#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
+#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
-/* like strdup except uses palloc */
-extern char *pstrdup(const char *pointer);
#endif /* PALLOC_H */
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: portal.h,v 1.23 2000/04/12 17:16:55 momjian Exp $
+ * $Id: portal.h,v 1.24 2000/06/28 03:33:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Note:
* A portal is an abstraction which represents the execution state of
- * a running query (or a fixed sequence of queries). The "blank portal" is
- * a portal with an InvalidName. This blank portal is in existance except
- * between calls to BlankPortalAssignName and GetPortalByName(NULL).
+ * a running query (or a fixed sequence of queries).
*
* Note:
* now that PQ calls can be made from within a backend, a portal
#include "executor/execdesc.h"
#include "nodes/memnodes.h"
-typedef struct PortalBlockData
-{
- AllocSetData setData;
- FixedItemData itemData;
-} PortalBlockData;
-
-typedef PortalBlockData *PortalBlock;
-typedef struct PortalD PortalD;
-typedef PortalD *Portal;
+typedef struct PortalD *Portal;
-struct PortalD
+typedef struct PortalD
{
- char *name; /* XXX PortalName */
- struct PortalVariableMemoryData variable;
- struct PortalHeapMemoryData heap;
- QueryDesc *queryDesc;
+ char *name; /* Portal's name */
+ MemoryContext heap; /* subsidiary memory */
+ QueryDesc *queryDesc; /* Info about query associated with portal */
TupleDesc attinfo;
EState *state;
- void (*cleanup) (Portal);
-};
+ void (*cleanup) (Portal); /* Cleanup routine (optional) */
+} PortalD;
/*
* PortalIsValid
*/
#define PortalIsValid(p) PointerIsValid(p)
-/*
- * Special portals (well, their names anyway)
- */
-#define VACPNAME ""
-#define TRUNCPNAME ""
-
-extern bool PortalNameIsSpecial(char *pname);
+extern void EnablePortalManager(void);
extern void AtEOXact_portals(void);
-extern void EnablePortalManager(bool on);
+extern Portal CreatePortal(char *name);
+extern void PortalDrop(Portal *portalP);
extern Portal GetPortalByName(char *name);
-extern Portal BlankPortalAssignName(char *name);
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
TupleDesc attinfo, EState *state,
void (*cleanup) (Portal portal));
extern QueryDesc *PortalGetQueryDesc(Portal portal);
extern EState *PortalGetState(Portal portal);
-extern Portal CreatePortal(char *name);
-extern void PortalDrop(Portal *portalP);
-extern void StartPortalAllocMode(AllocMode mode, Size limit);
-extern void EndPortalAllocMode(void);
-extern void PortalResetHeapMemory(Portal portal);
-extern PortalVariableMemory PortalGetVariableMemory(Portal portal);
-extern PortalHeapMemory PortalGetHeapMemory(Portal portal);
-extern void CommonSpecialPortalOpen(void);
-extern void CommonSpecialPortalClose(void);
-extern PortalVariableMemory CommonSpecialPortalGetMemory(void);
-extern bool CommonSpecialPortalIsOpen(void);
+extern MemoryContext PortalGetHeapMemory(Portal portal);
/* estimate of the maximum number of open portals a user would have,
- * used in initially sizing the PortalHashTable in EnablePortalManager()
+ * used in initially sizing the PortalHashTable in EnablePortalManager()
*/
#define PORTALS_PER_USER 10