First phase of memory management rewrite (see backend/utils/mmgr/README
for details). It doesn't really do that much yet, since there are no short-term memory contexts in the executor, but the infrastructure is in place and long-term contexts are handled reasonably. A few long- standing bugs have been fixed, such as 'VACUUM; anything' in a single query string crashing. Also, out-of-memory is now considered a recoverable ERROR, not FATAL. Eliminate a large amount of crufty, now-dead code in and around memory management. Fix problem with holding off SIGTRAP, SIGSEGV, etc in postmaster and backend startup.
This commit is contained in:
parent
b601c8d882
commit
1aebc3618a
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.9 2000/03/31 03:27:40 thomas Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.10 2000/06/28 03:30:53 tgl Exp $
|
||||
Genetic Optimizer
|
||||
-->
|
||||
|
||||
|
@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer
|
|||
<Sect2>
|
||||
<Title>Basic Improvements</Title>
|
||||
|
||||
<Sect3>
|
||||
<Title>Improve freeing of memory when query is already processed</Title>
|
||||
|
||||
<Para>
|
||||
With large <Command>join</Command> queries the computing time spent for the genetic query
|
||||
optimization seems to be a mere <Emphasis>fraction</Emphasis> of the time
|
||||
<ProductName>Postgres</ProductName>
|
||||
needs for freeing memory via routine <Function>MemoryContextFree</Function>,
|
||||
file <FileName>backend/utils/mmgr/mcxt.c</FileName>.
|
||||
Debugging showed that it get stucked in a loop of routine
|
||||
<Function>OrderedElemPop</Function>, file <FileName>backend/utils/mmgr/oset.c</FileName>.
|
||||
The same problems arise with long queries when using the normal
|
||||
<ProductName>Postgres</ProductName> query optimization algorithm.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<Sect3>
|
||||
<Title>Improve genetic algorithm parameter settings</Title>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.8 1999/12/30 22:58:10 momjian Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.9 2000/06/28 03:30:54 tgl Exp $
|
||||
Postgres documentation
|
||||
-->
|
||||
|
||||
|
@ -153,12 +153,13 @@ SELECT
|
|||
|
||||
<varlistentry>
|
||||
<term><computeroutput>
|
||||
NOTICE
|
||||
BlankPortalAssignName: portal "<replaceable class="parameter">cursorname</replaceable>" already exists
|
||||
NOTICE: Closing pre-existing portal "<replaceable class="parameter">cursorname</replaceable>"
|
||||
</computeroutput></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This error occurs if <replaceable class="parameter">cursorname</replaceable> is already declared.
|
||||
This message is reported if the same cursor name was already declared
|
||||
in the current transaction block. The previous definition is
|
||||
discarded.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.55 2000/06/17 00:09:34 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.56 2000/06/28 03:30:57 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
|
@ -237,8 +237,6 @@ install-headers: prebuildheaders $(SRCDIR)/include/config.h
|
|||
$(HEADERDIR)/utils/fmgroids.h
|
||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \
|
||||
$(HEADERDIR)/utils/palloc.h
|
||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/mcxt.h \
|
||||
$(HEADERDIR)/utils/mcxt.h
|
||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/access/attnum.h \
|
||||
$(HEADERDIR)/access/attnum.h
|
||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.71 2000/06/15 04:09:34 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.72 2000/06/28 03:31:04 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -1230,10 +1230,7 @@ heap_insert(Relation relation, HeapTuple tup)
|
|||
* ----------------
|
||||
*/
|
||||
if (!OidIsValid(tup->t_data->t_oid))
|
||||
{
|
||||
tup->t_data->t_oid = newoid();
|
||||
LastOidProcessed = tup->t_data->t_oid;
|
||||
}
|
||||
else
|
||||
CheckMaxObjectId(tup->t_data->t_oid);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.67 2000/06/18 22:43:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.68 2000/06/28 03:31:05 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Transaction aborts can now occur two ways:
|
||||
|
@ -18,14 +18,14 @@
|
|||
*
|
||||
* These two cases used to be treated identically, but now
|
||||
* we need to distinguish them. Why? consider the following
|
||||
* two situatuons:
|
||||
* two situations:
|
||||
*
|
||||
* case 1 case 2
|
||||
* ------ ------
|
||||
* 1) user types BEGIN 1) user types BEGIN
|
||||
* 2) user does something 2) user does something
|
||||
* 3) user does not like what 3) system aborts for some reason
|
||||
* she shes and types ABORT
|
||||
* she sees and types ABORT
|
||||
*
|
||||
* In case 1, we want to abort the transaction and return to the
|
||||
* default state. In case 2, there may be more commands coming
|
||||
|
@ -42,6 +42,15 @@
|
|||
* * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
|
||||
* * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
|
||||
*
|
||||
* Low-level transaction abort handling is divided into two phases:
|
||||
* * AbortTransaction() executes as soon as we realize the transaction
|
||||
* has failed. It should release all shared resources (locks etc)
|
||||
* so that we do not delay other backends unnecessarily.
|
||||
* * CleanupTransaction() executes when we finally see a user COMMIT
|
||||
* or ROLLBACK command; it cleans things up and gets us out of
|
||||
* the transaction internally. In particular, we mustn't destroy
|
||||
* TransactionCommandContext until this point.
|
||||
*
|
||||
* NOTES
|
||||
* This file is an attempt at a redesign of the upper layer
|
||||
* of the V1 transaction system which was too poorly thought
|
||||
|
@ -70,7 +79,7 @@
|
|||
* StartTransaction
|
||||
* CommitTransaction
|
||||
* AbortTransaction
|
||||
* UserAbortTransaction
|
||||
* CleanupTransaction
|
||||
*
|
||||
* are provided to do the lower level work like recording
|
||||
* the transaction status in the log and doing memory cleanup.
|
||||
|
@ -151,13 +160,15 @@
|
|||
#include "commands/async.h"
|
||||
#include "commands/sequence.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "executor/spi.h"
|
||||
#include "libpq/be-fsstubs.h"
|
||||
#include "storage/proc.h"
|
||||
#include "storage/sinval.h"
|
||||
#include "utils/temprel.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/portal.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/temprel.h"
|
||||
|
||||
extern bool SharedBufferChanged;
|
||||
|
||||
|
@ -165,6 +176,7 @@ static void AbortTransaction(void);
|
|||
static void AtAbort_Cache(void);
|
||||
static void AtAbort_Locks(void);
|
||||
static void AtAbort_Memory(void);
|
||||
static void AtCleanup_Memory(void);
|
||||
static void AtCommit_Cache(void);
|
||||
static void AtCommit_LocalCache(void);
|
||||
static void AtCommit_Locks(void);
|
||||
|
@ -172,6 +184,7 @@ static void AtCommit_Memory(void);
|
|||
static void AtStart_Cache(void);
|
||||
static void AtStart_Locks(void);
|
||||
static void AtStart_Memory(void);
|
||||
static void CleanupTransaction(void);
|
||||
static void CommitTransaction(void);
|
||||
static void RecordTransactionAbort(void);
|
||||
static void RecordTransactionCommit(void);
|
||||
|
@ -243,7 +256,7 @@ bool AMI_OVERRIDE = false;
|
|||
|
||||
/* --------------------------------
|
||||
* TranactionFlushEnabled()
|
||||
* SetTranactionFlushEnabled()
|
||||
* SetTransactionFlushEnabled()
|
||||
*
|
||||
* These are used to test and set the "TransactionFlushState"
|
||||
* varable. If this variable is true (the default), then
|
||||
|
@ -580,22 +593,35 @@ AtStart_Locks()
|
|||
static void
|
||||
AtStart_Memory()
|
||||
{
|
||||
Portal portal;
|
||||
MemoryContext portalContext;
|
||||
|
||||
/* ----------------
|
||||
* get the blank portal and its memory context
|
||||
* We shouldn't have any transaction contexts already.
|
||||
* ----------------
|
||||
*/
|
||||
portal = GetPortalByName(NULL);
|
||||
portalContext = (MemoryContext) PortalGetHeapMemory(portal);
|
||||
Assert(TopTransactionContext == NULL);
|
||||
Assert(TransactionCommandContext == NULL);
|
||||
|
||||
/* ----------------
|
||||
* tell system to allocate in the blank portal context
|
||||
* Create a toplevel context for the transaction.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(portalContext);
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
TopTransactionContext =
|
||||
AllocSetContextCreate(TopMemoryContext,
|
||||
"TopTransactionContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
/* ----------------
|
||||
* Create a statement-level context and make it active.
|
||||
* ----------------
|
||||
*/
|
||||
TransactionCommandContext =
|
||||
AllocSetContextCreate(TopTransactionContext,
|
||||
"TransactionCommandContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
MemoryContextSwitchTo(TransactionCommandContext);
|
||||
}
|
||||
|
||||
|
||||
|
@ -711,22 +737,21 @@ AtCommit_Locks()
|
|||
static void
|
||||
AtCommit_Memory()
|
||||
{
|
||||
Portal portal;
|
||||
|
||||
/* ----------------
|
||||
* Release all heap memory in the blank portal.
|
||||
* ----------------
|
||||
*/
|
||||
portal = GetPortalByName(NULL);
|
||||
PortalResetHeapMemory(portal);
|
||||
|
||||
/* ----------------
|
||||
* Now that we're "out" of a transaction, have the
|
||||
* system allocate things in the top memory context instead
|
||||
* of the blank portal memory context.
|
||||
* of per-transaction contexts.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* Release all transaction-local memory.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextDelete(TopTransactionContext);
|
||||
TopTransactionContext = NULL;
|
||||
TransactionCommandContext = NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -798,24 +823,52 @@ AtAbort_Locks()
|
|||
static void
|
||||
AtAbort_Memory()
|
||||
{
|
||||
Portal portal;
|
||||
|
||||
/* ----------------
|
||||
* Release all heap memory in the blank portal.
|
||||
* Make sure we are in a valid context (not a child of
|
||||
* TransactionCommandContext...)
|
||||
* ----------------
|
||||
*/
|
||||
portal = GetPortalByName(NULL);
|
||||
PortalResetHeapMemory(portal);
|
||||
MemoryContextSwitchTo(TransactionCommandContext);
|
||||
|
||||
/* ----------------
|
||||
* We do not want to destroy transaction contexts yet,
|
||||
* but it should be OK to delete any command-local memory.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* CleanupTransaction stuff
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* AtCleanup_Memory
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
AtCleanup_Memory()
|
||||
{
|
||||
/* ----------------
|
||||
* Now that we're "out" of a transaction, have the
|
||||
* system allocate things in the top memory context instead
|
||||
* of the blank portal memory context.
|
||||
* of per-transaction contexts.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* Release all transaction-local memory.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextDelete(TopTransactionContext);
|
||||
TopTransactionContext = NULL;
|
||||
TransactionCommandContext = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* interface routines
|
||||
* ----------------------------------------------------------------
|
||||
|
@ -854,6 +907,7 @@ StartTransaction()
|
|||
s->state = TRANS_START;
|
||||
|
||||
SetReindexProcessing(false);
|
||||
|
||||
/* ----------------
|
||||
* generate a new transaction id
|
||||
* ----------------
|
||||
|
@ -874,9 +928,9 @@ StartTransaction()
|
|||
* initialize the various transaction subsystems
|
||||
* ----------------
|
||||
*/
|
||||
AtStart_Memory();
|
||||
AtStart_Cache();
|
||||
AtStart_Locks();
|
||||
AtStart_Memory();
|
||||
|
||||
/* ----------------
|
||||
* Tell the trigger manager to we're starting a transaction
|
||||
|
@ -974,20 +1028,21 @@ CommitTransaction()
|
|||
}
|
||||
|
||||
RelationPurgeLocalRelation(true);
|
||||
AtEOXact_SPI();
|
||||
AtEOXact_nbtree();
|
||||
AtCommit_Cache();
|
||||
AtCommit_Locks();
|
||||
AtCommit_Memory();
|
||||
AtEOXact_Files();
|
||||
|
||||
SharedBufferChanged = false; /* safest place to do it */
|
||||
|
||||
/* ----------------
|
||||
* done with commit processing, set current transaction
|
||||
* state back to default
|
||||
* ----------------
|
||||
*/
|
||||
s->state = TRANS_DEFAULT;
|
||||
SharedBufferChanged = false;/* safest place to do it */
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
|
@ -1018,7 +1073,7 @@ AbortTransaction()
|
|||
return;
|
||||
|
||||
if (s->state != TRANS_INPROGRESS)
|
||||
elog(NOTICE, "AbortTransaction and not in in-progress state ");
|
||||
elog(NOTICE, "AbortTransaction and not in in-progress state");
|
||||
|
||||
/* ----------------
|
||||
* Tell the trigger manager that this transaction is about to be
|
||||
|
@ -1043,24 +1098,56 @@ AbortTransaction()
|
|||
AtAbort_Notify();
|
||||
CloseSequences();
|
||||
AtEOXact_portals();
|
||||
if (CommonSpecialPortalIsOpen())
|
||||
CommonSpecialPortalClose();
|
||||
RecordTransactionAbort();
|
||||
RelationPurgeLocalRelation(false);
|
||||
invalidate_temp_relations();
|
||||
AtEOXact_SPI();
|
||||
AtEOXact_nbtree();
|
||||
AtAbort_Cache();
|
||||
AtAbort_Locks();
|
||||
AtAbort_Memory();
|
||||
AtEOXact_Files();
|
||||
|
||||
SharedBufferChanged = false; /* safest place to do it */
|
||||
|
||||
/* ----------------
|
||||
* State remains TRANS_ABORT until CleanupTransaction().
|
||||
* ----------------
|
||||
*/
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* CleanupTransaction
|
||||
*
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
CleanupTransaction()
|
||||
{
|
||||
TransactionState s = CurrentTransactionState;
|
||||
|
||||
if (s->state == TRANS_DISABLED)
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* State should still be TRANS_ABORT from AbortTransaction().
|
||||
* ----------------
|
||||
*/
|
||||
if (s->state != TRANS_ABORT)
|
||||
elog(FATAL, "CleanupTransaction and not in abort state");
|
||||
|
||||
/* ----------------
|
||||
* do abort cleanup processing
|
||||
* ----------------
|
||||
*/
|
||||
AtCleanup_Memory();
|
||||
|
||||
/* ----------------
|
||||
* done with abort processing, set current transaction
|
||||
* state back to default
|
||||
* ----------------
|
||||
*/
|
||||
s->state = TRANS_DEFAULT;
|
||||
SharedBufferChanged = false;/* safest place to do it */
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
|
@ -1133,7 +1220,7 @@ StartTransactionCommand()
|
|||
/* ----------------
|
||||
* This means we somehow aborted and the last call to
|
||||
* CommitTransactionCommand() didn't clear the state so
|
||||
* we remain in the ENDABORT state and mabey next time
|
||||
* we remain in the ENDABORT state and maybe next time
|
||||
* we get to CommitTransactionCommand() the state will
|
||||
* get reset to default.
|
||||
* ----------------
|
||||
|
@ -1142,6 +1229,13 @@ StartTransactionCommand()
|
|||
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must switch to TransactionCommandContext before returning.
|
||||
* This is already done if we called StartTransaction, otherwise not.
|
||||
*/
|
||||
Assert(TransactionCommandContext != NULL);
|
||||
MemoryContextSwitchTo(TransactionCommandContext);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
|
@ -1181,28 +1275,25 @@ CommitTransactionCommand()
|
|||
* command counter and return. Someday we may free resources
|
||||
* local to the command.
|
||||
*
|
||||
* That someday is today, at least for memory allocated by
|
||||
* command in the BlankPortal' HeapMemory context.
|
||||
* That someday is today, at least for memory allocated in
|
||||
* TransactionCommandContext.
|
||||
* - vadim 03/25/97
|
||||
* ----------------
|
||||
*/
|
||||
case TBLOCK_INPROGRESS:
|
||||
CommandCounterIncrement();
|
||||
#ifdef TBL_FREE_CMD_MEMORY
|
||||
EndPortalAllocMode();
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
#endif
|
||||
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
||||
break;
|
||||
|
||||
/* ----------------
|
||||
* This is the case when we just got the "END TRANSACTION"
|
||||
* statement, so we go back to the default state and
|
||||
* commit the transaction.
|
||||
* statement, so we commit the transaction and go back to
|
||||
* the default state.
|
||||
* ----------------
|
||||
*/
|
||||
case TBLOCK_END:
|
||||
s->blockState = TBLOCK_DEFAULT;
|
||||
CommitTransaction();
|
||||
s->blockState = TBLOCK_DEFAULT;
|
||||
break;
|
||||
|
||||
/* ----------------
|
||||
|
@ -1218,10 +1309,11 @@ CommitTransactionCommand()
|
|||
/* ----------------
|
||||
* Here we were in an aborted transaction block which
|
||||
* just processed the "END TRANSACTION" command from the
|
||||
* user, so now we return the to default state.
|
||||
* user, so clean up and return to the default state.
|
||||
* ----------------
|
||||
*/
|
||||
case TBLOCK_ENDABORT:
|
||||
CleanupTransaction();
|
||||
s->blockState = TBLOCK_DEFAULT;
|
||||
break;
|
||||
}
|
||||
|
@ -1240,11 +1332,12 @@ AbortCurrentTransaction()
|
|||
{
|
||||
/* ----------------
|
||||
* if we aren't in a transaction block, we
|
||||
* just do our usual abort transaction.
|
||||
* just do the basic abort & cleanup transaction.
|
||||
* ----------------
|
||||
*/
|
||||
case TBLOCK_DEFAULT:
|
||||
AbortTransaction();
|
||||
CleanupTransaction();
|
||||
break;
|
||||
|
||||
/* ----------------
|
||||
|
@ -1257,6 +1350,7 @@ AbortCurrentTransaction()
|
|||
case TBLOCK_BEGIN:
|
||||
s->blockState = TBLOCK_ABORT;
|
||||
AbortTransaction();
|
||||
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
||||
break;
|
||||
|
||||
/* ----------------
|
||||
|
@ -1269,6 +1363,7 @@ AbortCurrentTransaction()
|
|||
case TBLOCK_INPROGRESS:
|
||||
s->blockState = TBLOCK_ABORT;
|
||||
AbortTransaction();
|
||||
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
||||
break;
|
||||
|
||||
/* ----------------
|
||||
|
@ -1281,6 +1376,7 @@ AbortCurrentTransaction()
|
|||
case TBLOCK_END:
|
||||
s->blockState = TBLOCK_DEFAULT;
|
||||
AbortTransaction();
|
||||
CleanupTransaction();
|
||||
break;
|
||||
|
||||
/* ----------------
|
||||
|
@ -1297,10 +1393,11 @@ AbortCurrentTransaction()
|
|||
* Here we were in an aborted transaction block which
|
||||
* just processed the "END TRANSACTION" command but somehow
|
||||
* aborted again.. since we must have done the abort
|
||||
* processing, we return to the default state.
|
||||
* processing, we clean up and return to the default state.
|
||||
* ----------------
|
||||
*/
|
||||
case TBLOCK_ENDABORT:
|
||||
CleanupTransaction();
|
||||
s->blockState = TBLOCK_DEFAULT;
|
||||
break;
|
||||
}
|
||||
|
@ -1394,13 +1491,14 @@ EndTransactionBlock(void)
|
|||
}
|
||||
|
||||
/* ----------------
|
||||
* We should not get here, but if we do, we go to the ENDABORT
|
||||
* state after printing a warning. The upcoming call to
|
||||
* here, the user issued COMMIT when not inside a transaction.
|
||||
* Issue a notice and go to abort state. The upcoming call to
|
||||
* CommitTransactionCommand() will then put us back into the
|
||||
* default state.
|
||||
* ----------------
|
||||
*/
|
||||
elog(NOTICE, "COMMIT: no transaction in progress");
|
||||
AbortTransaction();
|
||||
s->blockState = TBLOCK_ENDABORT;
|
||||
}
|
||||
|
||||
|
@ -1427,29 +1525,23 @@ AbortTransactionBlock(void)
|
|||
* here we were inside a transaction block something
|
||||
* screwed up inside the system so we enter the abort state,
|
||||
* do the abort processing and then return.
|
||||
* We remain in the abort state until we see the upcoming
|
||||
* We remain in the abort state until we see an
|
||||
* END TRANSACTION command.
|
||||
* ----------------
|
||||
*/
|
||||
s->blockState = TBLOCK_ABORT;
|
||||
|
||||
/* ----------------
|
||||
* do abort processing and return
|
||||
* ----------------
|
||||
*/
|
||||
AbortTransaction();
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* this case should not be possible, because it would mean
|
||||
* the user entered an "abort" from outside a transaction block.
|
||||
* So we print an error message, abort the transaction and
|
||||
* enter the "ENDABORT" state so we will end up in the default
|
||||
* state after the upcoming CommitTransactionCommand().
|
||||
* here, the user issued ABORT when not inside a transaction.
|
||||
* Issue a notice and go to abort state. The upcoming call to
|
||||
* CommitTransactionCommand() will then put us back into the
|
||||
* default state.
|
||||
* ----------------
|
||||
*/
|
||||
elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
|
||||
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
||||
AbortTransaction();
|
||||
s->blockState = TBLOCK_ENDABORT;
|
||||
}
|
||||
|
@ -1495,27 +1587,16 @@ UserAbortTransactionBlock()
|
|||
* ----------------
|
||||
*/
|
||||
s->blockState = TBLOCK_ABORT;
|
||||
|
||||
/* ----------------
|
||||
* do abort processing
|
||||
* ----------------
|
||||
*/
|
||||
AbortTransaction();
|
||||
|
||||
/* ----------------
|
||||
* change to the end abort state and return
|
||||
* ----------------
|
||||
*/
|
||||
s->blockState = TBLOCK_ENDABORT;
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* this case should not be possible, because it would mean
|
||||
* the user entered a "rollback" from outside a transaction block.
|
||||
* So we print an error message, abort the transaction and
|
||||
* enter the "ENDABORT" state so we will end up in the default
|
||||
* state after the upcoming CommitTransactionCommand().
|
||||
* here, the user issued ABORT when not inside a transaction.
|
||||
* Issue a notice and go to abort state. The upcoming call to
|
||||
* CommitTransactionCommand() will then put us back into the
|
||||
* default state.
|
||||
* ----------------
|
||||
*/
|
||||
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
||||
|
@ -1540,7 +1621,10 @@ AbortOutOfAnyTransaction()
|
|||
* Get out of any low-level transaction
|
||||
*/
|
||||
if (s->state != TRANS_DEFAULT)
|
||||
{
|
||||
AbortTransaction();
|
||||
CleanupTransaction();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now reset the high-level state
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.87 2000/06/22 22:31:17 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.88 2000/06/28 03:31:09 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -34,14 +34,14 @@
|
|||
#include "miscadmin.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/exc.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/guc.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/portal.h"
|
||||
|
||||
|
||||
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
|
||||
|
||||
extern void BaseInit(void);
|
||||
extern void StartupXLOG(void);
|
||||
extern void ShutdownXLOG(void);
|
||||
extern void BootStrapXLOG(void);
|
||||
|
@ -144,8 +144,8 @@ static Datum values[MAXATTR]; /* corresponding attribute values */
|
|||
int numattr; /* number of attributes for cur. rel */
|
||||
|
||||
int DebugMode;
|
||||
static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
|
||||
* context */
|
||||
|
||||
static MemoryContext nogc = NULL; /* special no-gc mem context */
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
@ -240,6 +240,17 @@ BootstrapMain(int argc, char *argv[])
|
|||
|
||||
MyProcPid = getpid();
|
||||
|
||||
/*
|
||||
* Fire up essential subsystems: error and memory management
|
||||
*
|
||||
* If we are running under the postmaster, this is done already.
|
||||
*/
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
EnableExceptionHandling(true);
|
||||
MemoryContextInit();
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* process command arguments
|
||||
* ----------------
|
||||
|
@ -428,7 +439,6 @@ boot_openrel(char *relname)
|
|||
|
||||
if (Typ == (struct typmap **) NULL)
|
||||
{
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
rel = heap_openr(TypeRelationName, NoLock);
|
||||
Assert(rel);
|
||||
scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
|
||||
|
@ -445,13 +455,13 @@ boot_openrel(char *relname)
|
|||
while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
|
||||
{
|
||||
(*app)->am_oid = tup->t_data->t_oid;
|
||||
memmove((char *) &(*app++)->am_typ,
|
||||
(char *) GETSTRUCT(tup),
|
||||
sizeof((*app)->am_typ));
|
||||
memcpy((char *) &(*app)->am_typ,
|
||||
(char *) GETSTRUCT(tup),
|
||||
sizeof((*app)->am_typ));
|
||||
app++;
|
||||
}
|
||||
heap_endscan(scan);
|
||||
heap_close(rel, NoLock);
|
||||
EndPortalAllocMode();
|
||||
}
|
||||
|
||||
if (reldesc != NULL)
|
||||
|
@ -1088,10 +1098,14 @@ index_register(char *heap,
|
|||
* them later.
|
||||
*/
|
||||
|
||||
if (nogc == (GlobalMemory) NULL)
|
||||
nogc = CreateGlobalMemory("BootstrapNoGC");
|
||||
if (nogc == NULL)
|
||||
nogc = AllocSetContextCreate((MemoryContext) NULL,
|
||||
"BootstrapNoGC",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
|
||||
oldcxt = MemoryContextSwitchTo(nogc);
|
||||
|
||||
newind = (IndexList *) palloc(sizeof(IndexList));
|
||||
newind->il_heap = pstrdup(heap);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.133 2000/06/18 22:43:55 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.134 2000/06/28 03:31:22 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -188,38 +188,27 @@ heap_create(char *relname,
|
|||
relname);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* switch to the cache context so that we don't lose
|
||||
* allocations at the end of this transaction, I guess.
|
||||
* -cim 6/14/90
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
|
||||
/* ----------------
|
||||
* real ugly stuff to assign the proper relid in the relation
|
||||
* descriptor follows.
|
||||
* ----------------
|
||||
*/
|
||||
if (relname && !strcmp(RelationRelationName, relname))
|
||||
if (relname && strcmp(RelationRelationName, relname) == 0)
|
||||
{
|
||||
relid = RelOid_pg_class;
|
||||
nailme = true;
|
||||
}
|
||||
else if (relname && !strcmp(AttributeRelationName, relname))
|
||||
else if (relname && strcmp(AttributeRelationName, relname) == 0)
|
||||
{
|
||||
relid = RelOid_pg_attribute;
|
||||
nailme = true;
|
||||
}
|
||||
else if (relname && !strcmp(ProcedureRelationName, relname))
|
||||
else if (relname && strcmp(ProcedureRelationName, relname) == 0)
|
||||
{
|
||||
relid = RelOid_pg_proc;
|
||||
nailme = true;
|
||||
}
|
||||
else if (relname && !strcmp(TypeRelationName, relname))
|
||||
else if (relname && strcmp(TypeRelationName, relname) == 0)
|
||||
{
|
||||
relid = RelOid_pg_type;
|
||||
nailme = true;
|
||||
|
@ -234,6 +223,15 @@ heap_create(char *relname,
|
|||
(int) MyProcPid, uniqueId++);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* switch to the cache context to create the relcache entry.
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* allocate a new relation descriptor.
|
||||
* ----------------
|
||||
|
@ -287,6 +285,8 @@ heap_create(char *relname,
|
|||
|
||||
/* ----------------
|
||||
* have the storage manager create the relation.
|
||||
*
|
||||
* XXX shouldn't we switch out of CacheMemoryContext for that?
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.119 2000/06/18 22:43:55 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.120 2000/06/28 03:31:23 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -442,10 +442,10 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
|||
* context changes
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
|
||||
|
||||
|
@ -904,16 +904,16 @@ InitIndexStrategy(int numatts,
|
|||
* it will be lost at the end of the transaction.
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
strategy = (IndexStrategy)
|
||||
MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
|
||||
strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
|
||||
strsize);
|
||||
|
||||
if (amsupport > 0)
|
||||
{
|
||||
strsize = numatts * (amsupport * sizeof(RegProcedure));
|
||||
support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
|
||||
support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
|
||||
strsize);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.44 2000/06/14 04:53:44 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.45 2000/06/28 03:31:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -217,8 +217,7 @@ ProcedureCreate(char *procedureName,
|
|||
|
||||
if (languageObjectId == SQLlanguageId)
|
||||
{
|
||||
querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount,
|
||||
FALSE);
|
||||
querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount);
|
||||
/* typecheck return value */
|
||||
pg_checkretval(typeObjectId, querytree_list);
|
||||
}
|
||||
|
|
|
@ -8,13 +8,9 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.80 2000/06/15 04:09:45 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.81 2000/06/28 03:31:28 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The PortalExecutorHeapMemory crap needs to be eliminated
|
||||
* by designing a better executor / portal processing memory
|
||||
* interface.
|
||||
*
|
||||
* The PerformAddAttribute() code, like most of the relation
|
||||
* manipulating code in the commands/ directory, should go
|
||||
* someplace closer to the lib/catalog code.
|
||||
|
@ -40,13 +36,6 @@
|
|||
#include "parser/parse.h"
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
|
||||
/* ----------------
|
||||
* PortalExecutorHeapMemory stuff
|
||||
*
|
||||
* This is where the XXXSuperDuperHacky code was. -cim 3/15/90
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContext PortalExecutorHeapMemory = NULL;
|
||||
|
||||
/* --------------------------------
|
||||
* PortalCleanup
|
||||
|
@ -55,7 +44,7 @@ MemoryContext PortalExecutorHeapMemory = NULL;
|
|||
void
|
||||
PortalCleanup(Portal portal)
|
||||
{
|
||||
MemoryContext context;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
/* ----------------
|
||||
* sanity checks
|
||||
|
@ -68,8 +57,7 @@ PortalCleanup(Portal portal)
|
|||
* set proper portal-executor context before calling ExecMain.
|
||||
* ----------------
|
||||
*/
|
||||
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
|
||||
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
|
||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
/* ----------------
|
||||
* tell the executor to shutdown the query
|
||||
|
@ -81,8 +69,7 @@ PortalCleanup(Portal portal)
|
|||
* switch back to previous context
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(context);
|
||||
PortalExecutorHeapMemory = (MemoryContext) NULL;
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
|
@ -99,7 +86,7 @@ PerformPortalFetch(char *name,
|
|||
Portal portal;
|
||||
int feature;
|
||||
QueryDesc *queryDesc;
|
||||
MemoryContext context;
|
||||
MemoryContext oldcontext;
|
||||
Const limcount;
|
||||
|
||||
/* ----------------
|
||||
|
@ -108,7 +95,7 @@ PerformPortalFetch(char *name,
|
|||
*/
|
||||
if (name == NULL)
|
||||
{
|
||||
elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
|
||||
elog(NOTICE, "PerformPortalFetch: missing portal name");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -120,12 +107,11 @@ PerformPortalFetch(char *name,
|
|||
limcount.type = T_Const;
|
||||
limcount.consttype = INT4OID;
|
||||
limcount.constlen = sizeof(int4);
|
||||
limcount.constvalue = (Datum) count;
|
||||
limcount.constisnull = FALSE;
|
||||
limcount.constbyval = TRUE;
|
||||
limcount.constisset = FALSE;
|
||||
limcount.constiscast = FALSE;
|
||||
|
||||
limcount.constvalue = Int32GetDatum(count);
|
||||
limcount.constisnull = false;
|
||||
limcount.constbyval = true;
|
||||
limcount.constisset = false;
|
||||
limcount.constiscast = false;
|
||||
|
||||
/* ----------------
|
||||
* get the portal from the portal name
|
||||
|
@ -143,9 +129,7 @@ PerformPortalFetch(char *name,
|
|||
* switch into the portal context
|
||||
* ----------------
|
||||
*/
|
||||
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
|
||||
|
||||
AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
|
||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
/* ----------------
|
||||
* setup "feature" to tell the executor what direction and
|
||||
|
@ -174,8 +158,7 @@ PerformPortalFetch(char *name,
|
|||
|
||||
BeginCommand(name,
|
||||
queryDesc->operation,
|
||||
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
|
||||
* */
|
||||
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc) */
|
||||
false, /* portal fetches don't end up in
|
||||
* relations */
|
||||
false, /* this is a portal fetch, not a "retrieve
|
||||
|
@ -187,8 +170,6 @@ PerformPortalFetch(char *name,
|
|||
* execute the portal fetch operation
|
||||
* ----------------
|
||||
*/
|
||||
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
|
||||
|
||||
ExecutorRun(queryDesc, PortalGetState(portal), feature,
|
||||
(Node *) NULL, (Node *) &limcount);
|
||||
|
||||
|
@ -196,18 +177,16 @@ PerformPortalFetch(char *name,
|
|||
pfree(queryDesc);
|
||||
|
||||
/* ----------------
|
||||
* Note: the "end-of-command" tag is returned by higher-level
|
||||
* utility code
|
||||
*
|
||||
* Return blank portal for now.
|
||||
* Otherwise, this named portal will be cleaned.
|
||||
* Note: portals will only be supported within a BEGIN...END
|
||||
* block in the near future. Later, someone will fix it to
|
||||
* do what is possible across transaction boundries.
|
||||
* Switch back to old context.
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
/* ----------------
|
||||
* Note: the "end-of-command" tag is returned by higher-level
|
||||
* utility code
|
||||
* ----------------
|
||||
*/
|
||||
MemoryContextSwitchTo(
|
||||
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
|
@ -225,15 +204,10 @@ PerformPortalClose(char *name, CommandDest dest)
|
|||
*/
|
||||
if (name == NULL)
|
||||
{
|
||||
elog(NOTICE, "PerformPortalClose: blank portal unsupported");
|
||||
elog(NOTICE, "PerformPortalClose: missing portal name");
|
||||
return;
|
||||
}
|
||||
|
||||
if (PortalNameIsSpecial(name))
|
||||
elog(ERROR,
|
||||
"The portal name \"%s\" is reserved for internal use",
|
||||
name);
|
||||
|
||||
/* ----------------
|
||||
* get the portal from the portal name
|
||||
* ----------------
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.31 2000/06/17 23:41:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.32 2000/06/28 03:31:28 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -39,7 +39,6 @@
|
|||
#include "utils/fmgroids.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "miscadmin.h" /* ReindexDatabase() */
|
||||
#include "utils/portal.h" /* ReindexDatabase() */
|
||||
#include "catalog/catalog.h" /* ReindexDatabase() */
|
||||
|
||||
#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
|
||||
|
@ -764,7 +763,6 @@ ReindexTable(const char *name, bool force)
|
|||
* "ERROR" if table nonexistent.
|
||||
* ...
|
||||
*/
|
||||
extern Oid MyDatabaseId;
|
||||
void
|
||||
ReindexDatabase(const char *dbname, bool force, bool all)
|
||||
{
|
||||
|
@ -780,7 +778,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||
Oid db_id;
|
||||
char *username;
|
||||
ScanKeyData scankey;
|
||||
PortalVariableMemory pmem;
|
||||
MemoryContext private_context;
|
||||
MemoryContext old;
|
||||
int relcnt,
|
||||
relalc,
|
||||
|
@ -808,16 +806,34 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||
db_id = dbtuple->t_data->t_oid;
|
||||
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
|
||||
heap_endscan(scan);
|
||||
heap_close(relation, NoLock);
|
||||
|
||||
if (user_id != db_owner && !superuser)
|
||||
elog(ERROR, "REINDEX DATABASE: Permission denied.");
|
||||
|
||||
if (db_id != MyDatabaseId)
|
||||
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
|
||||
|
||||
heap_close(relation, NoLock);
|
||||
/*
|
||||
* We cannot run inside a user transaction block; if we were
|
||||
* inside a transaction, then our commit- and
|
||||
* start-transaction-command calls would not have the intended effect!
|
||||
*/
|
||||
if (IsTransactionBlock())
|
||||
elog(ERROR, "REINDEX DATABASE cannot run inside a BEGIN/END block");
|
||||
|
||||
/*
|
||||
* Create a memory context that will survive forced transaction commits
|
||||
* we do below. Since it is a child of QueryContext, it will go away
|
||||
* eventually even if we suffer an error; there's no need for special
|
||||
* abort cleanup logic.
|
||||
*/
|
||||
private_context = AllocSetContextCreate(QueryContext,
|
||||
"ReindexDatabase",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
CommonSpecialPortalOpen();
|
||||
pmem = CommonSpecialPortalGetMemory();
|
||||
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
|
||||
scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL);
|
||||
relcnt = relalc = 0;
|
||||
|
@ -832,7 +848,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||
}
|
||||
if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
|
||||
{
|
||||
old = MemoryContextSwitchTo((MemoryContext) pmem);
|
||||
old = MemoryContextSwitchTo(private_context);
|
||||
if (relcnt == 0)
|
||||
{
|
||||
relalc = oncealc;
|
||||
|
@ -859,6 +875,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||
elog(NOTICE, "relation %d was reindexed", relids[i]);
|
||||
CommitTransactionCommand();
|
||||
}
|
||||
CommonSpecialPortalClose();
|
||||
StartTransactionCommand();
|
||||
|
||||
MemoryContextDelete(private_context);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.69 2000/06/08 22:37:01 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.70 2000/06/28 03:31:28 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1029,8 +1029,8 @@ ltrmark:;
|
|||
* end.
|
||||
* ----------
|
||||
*/
|
||||
static GlobalMemory deftrig_gcxt = NULL;
|
||||
static GlobalMemory deftrig_cxt = NULL;
|
||||
static MemoryContext deftrig_gcxt = NULL;
|
||||
static MemoryContext deftrig_cxt = NULL;
|
||||
|
||||
/* ----------
|
||||
* Global data that tells which triggers are actually in
|
||||
|
@ -1104,7 +1104,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
|
|||
* as the current and return that.
|
||||
* ----------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||
|
||||
trigstate = (DeferredTriggerStatus)
|
||||
palloc(sizeof(DeferredTriggerStatusData));
|
||||
|
@ -1366,7 +1366,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
|||
int
|
||||
DeferredTriggerInit(void)
|
||||
{
|
||||
deftrig_gcxt = CreateGlobalMemory("DeferredTriggerSession");
|
||||
deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
|
||||
"DeferredTriggerSession",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1395,8 +1400,12 @@ DeferredTriggerBeginXact(void)
|
|||
* from the per session context to here.
|
||||
* ----------
|
||||
*/
|
||||
deftrig_cxt = CreateGlobalMemory("DeferredTriggerXact");
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
||||
deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
|
||||
"DeferredTriggerXact",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||
|
||||
deftrig_all_isset = deftrig_dfl_all_isset;
|
||||
deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
|
||||
|
@ -1461,7 +1470,7 @@ DeferredTriggerEndXact(void)
|
|||
|
||||
deferredTriggerInvokeEvents(false);
|
||||
|
||||
GlobalMemoryDestroy(deftrig_cxt);
|
||||
MemoryContextDelete(deftrig_cxt);
|
||||
deftrig_cxt = NULL;
|
||||
}
|
||||
|
||||
|
@ -1484,7 +1493,7 @@ DeferredTriggerAbortXact(void)
|
|||
if (deftrig_cxt == NULL)
|
||||
return;
|
||||
|
||||
GlobalMemoryDestroy(deftrig_cxt);
|
||||
MemoryContextDelete(deftrig_cxt);
|
||||
deftrig_cxt = NULL;
|
||||
}
|
||||
|
||||
|
@ -1521,7 +1530,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||
* ... outside of a transaction block
|
||||
* ----------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
|
||||
|
||||
/* ----------
|
||||
* Drop all information about individual trigger states per
|
||||
|
@ -1555,7 +1564,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||
* ... inside of a transaction block
|
||||
* ----------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||
|
||||
/* ----------
|
||||
* Drop all information about individual trigger states per
|
||||
|
@ -1701,7 +1710,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||
* states of individual triggers on session level.
|
||||
* ----------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
|
||||
|
||||
foreach(l, loid)
|
||||
{
|
||||
|
@ -1739,7 +1748,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||
* states of individual triggers on transaction level.
|
||||
* ----------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||
|
||||
foreach(l, loid)
|
||||
{
|
||||
|
@ -1827,7 +1836,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||
* Create a new event
|
||||
* ----------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||
|
||||
ntriggers = rel->trigdesc->n_after_row[event];
|
||||
triggers = rel->trigdesc->tg_after_row[event];
|
||||
|
@ -2022,7 +2031,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||
* Anything's fine up to here. Add the new event to the queue.
|
||||
* ----------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
||||
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||
deferredTriggerAddEvent(new_event);
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* user.c
|
||||
* use pg_exec_query to create a new user in the catalog
|
||||
* Commands for manipulating users and groups.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.61 2000/06/25 14:24:59 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.62 2000/06/28 03:31:28 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.161 2000/06/28 03:31:28 tgl Exp $
|
||||
*
|
||||
|
||||
*-------------------------------------------------------------------------
|
||||
|
@ -35,7 +35,6 @@
|
|||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/inval.h"
|
||||
#include "utils/portal.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/temprel.h"
|
||||
|
@ -48,9 +47,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
bool CommonSpecialPortalInUse = false;
|
||||
|
||||
static Portal vac_portal;
|
||||
static MemoryContext vac_context = NULL;
|
||||
|
||||
static int MESSAGE_LEVEL; /* message level */
|
||||
|
||||
|
@ -82,14 +79,13 @@ static int vac_cmp_offno(const void *left, const void *right);
|
|||
static int vac_cmp_vtlinks(const void *left, const void *right);
|
||||
static bool enough_space(VacPage vacpage, Size len);
|
||||
static char *show_rusage(struct rusage * ru0);
|
||||
/* CommonSpecialPortal function at the bottom */
|
||||
|
||||
|
||||
void
|
||||
vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
||||
{
|
||||
NameData VacRel;
|
||||
Name VacRelName;
|
||||
PortalVariableMemory pmem;
|
||||
MemoryContext old;
|
||||
List *le;
|
||||
List *anal_cols2 = NIL;
|
||||
|
@ -114,8 +110,18 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
|||
else
|
||||
MESSAGE_LEVEL = DEBUG;
|
||||
|
||||
/* Create special portal for cross-transaction storage */
|
||||
CommonSpecialPortalOpen();
|
||||
/*
|
||||
* Create special memory context for cross-transaction storage.
|
||||
*
|
||||
* Since it is a child of QueryContext, it will go away eventually
|
||||
* even if we suffer an error; there's no need for special abort
|
||||
* cleanup logic.
|
||||
*/
|
||||
vac_context = AllocSetContextCreate(QueryContext,
|
||||
"Vacuum",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
/* vacrel gets de-allocated on xact commit, so copy it to safe storage */
|
||||
if (vacrel)
|
||||
|
@ -127,8 +133,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
|||
VacRelName = NULL;
|
||||
|
||||
/* must also copy the column list, if any, to safe storage */
|
||||
pmem = CommonSpecialPortalGetMemory();
|
||||
old = MemoryContextSwitchTo((MemoryContext) pmem);
|
||||
old = MemoryContextSwitchTo(vac_context);
|
||||
foreach(le, anal_cols)
|
||||
{
|
||||
char *col = (char *) lfirst(le);
|
||||
|
@ -198,11 +203,16 @@ vacuum_shutdown()
|
|||
*/
|
||||
unlink(RELCACHE_INIT_FILENAME);
|
||||
|
||||
/* Clean up working storage */
|
||||
CommonSpecialPortalClose();
|
||||
|
||||
/* matches the CommitTransaction in PostgresMain() */
|
||||
StartTransactionCommand();
|
||||
|
||||
/*
|
||||
* Clean up working storage --- note we must do this after
|
||||
* StartTransactionCommand, else we might be trying to delete
|
||||
* the active context!
|
||||
*/
|
||||
MemoryContextDelete(vac_context);
|
||||
vac_context = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -239,8 +249,6 @@ getrels(NameData *VacRelP)
|
|||
TupleDesc tupdesc;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
PortalVariableMemory portalmem;
|
||||
MemoryContext old;
|
||||
VRelList vrl,
|
||||
cur;
|
||||
Datum d;
|
||||
|
@ -276,7 +284,6 @@ getrels(NameData *VacRelP)
|
|||
F_CHAREQ, CharGetDatum('r'));
|
||||
}
|
||||
|
||||
portalmem = CommonSpecialPortalGetMemory();
|
||||
vrl = cur = (VRelList) NULL;
|
||||
|
||||
rel = heap_openr(RelationRelationName, AccessShareLock);
|
||||
|
@ -302,25 +309,26 @@ getrels(NameData *VacRelP)
|
|||
}
|
||||
|
||||
/* get a relation list entry for this guy */
|
||||
old = MemoryContextSwitchTo((MemoryContext) portalmem);
|
||||
if (vrl == (VRelList) NULL)
|
||||
vrl = cur = (VRelList) palloc(sizeof(VRelListData));
|
||||
vrl = cur = (VRelList)
|
||||
MemoryContextAlloc(vac_context, sizeof(VRelListData));
|
||||
else
|
||||
{
|
||||
cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
|
||||
cur->vrl_next = (VRelList)
|
||||
MemoryContextAlloc(vac_context, sizeof(VRelListData));
|
||||
cur = cur->vrl_next;
|
||||
}
|
||||
MemoryContextSwitchTo(old);
|
||||
|
||||
cur->vrl_relid = tuple->t_data->t_oid;
|
||||
cur->vrl_next = (VRelList) NULL;
|
||||
}
|
||||
if (found == false)
|
||||
elog(NOTICE, "Vacuum: table not found");
|
||||
|
||||
heap_endscan(scan);
|
||||
heap_close(rel, AccessShareLock);
|
||||
|
||||
if (!found)
|
||||
elog(NOTICE, "Vacuum: table not found");
|
||||
|
||||
CommitTransactionCommand();
|
||||
|
||||
return vrl;
|
||||
|
@ -2275,62 +2283,6 @@ vac_cmp_vtlinks(const void *left, const void *right)
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* This routines handle a special cross-transaction portal.
|
||||
* However it is automatically closed in case of abort.
|
||||
*/
|
||||
void
|
||||
CommonSpecialPortalOpen(void)
|
||||
{
|
||||
char *pname;
|
||||
|
||||
|
||||
if (CommonSpecialPortalInUse)
|
||||
elog(ERROR, "CommonSpecialPortal is in use");
|
||||
|
||||
/*
|
||||
* Create a portal for safe memory across transactions. We need to
|
||||
* palloc the name space for it because our hash function expects the
|
||||
* name to be on a longword boundary. CreatePortal copies the name to
|
||||
* safe storage for us.
|
||||
*/
|
||||
pname = pstrdup(VACPNAME);
|
||||
vac_portal = CreatePortal(pname);
|
||||
pfree(pname);
|
||||
|
||||
/*
|
||||
* Set flag to indicate that vac_portal must be removed after an error.
|
||||
* This global variable is checked in the transaction manager on xact
|
||||
* abort, and the routine CommonSpecialPortalClose() is called if
|
||||
* necessary.
|
||||
*/
|
||||
CommonSpecialPortalInUse = true;
|
||||
}
|
||||
|
||||
void
|
||||
CommonSpecialPortalClose(void)
|
||||
{
|
||||
/* Clear flag first, to avoid recursion if PortalDrop elog's */
|
||||
CommonSpecialPortalInUse = false;
|
||||
|
||||
/*
|
||||
* Release our portal for cross-transaction memory.
|
||||
*/
|
||||
PortalDrop(&vac_portal);
|
||||
}
|
||||
|
||||
PortalVariableMemory
|
||||
CommonSpecialPortalGetMemory(void)
|
||||
{
|
||||
return PortalGetVariableMemory(vac_portal);
|
||||
}
|
||||
|
||||
bool
|
||||
CommonSpecialPortalIsOpen(void)
|
||||
{
|
||||
return CommonSpecialPortalInUse;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_indices(Relation relation, int *nindices, Relation **Irel)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.34 2000/05/28 17:55:55 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.35 2000/06/28 03:31:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -87,8 +87,8 @@ init_execution_state(FunctionCachePtr fcache)
|
|||
nextes = newes;
|
||||
preves = (execution_state *) NULL;
|
||||
|
||||
queryTree_list = pg_parse_and_rewrite(fcache->src, fcache->argOidVect,
|
||||
nargs, FALSE);
|
||||
queryTree_list = pg_parse_and_rewrite(fcache->src,
|
||||
fcache->argOidVect, nargs);
|
||||
|
||||
foreach(qtl_item, queryTree_list)
|
||||
{
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.67 2000/06/15 03:32:09 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.68 2000/06/28 03:31:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -265,7 +265,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
|
|||
else
|
||||
newVal = FunctionCallInvoke(&fcinfo);
|
||||
if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
|
||||
pfree(peraggstate->value1);
|
||||
pfree(DatumGetPointer(peraggstate->value1));
|
||||
peraggstate->value1 = newVal;
|
||||
peraggstate->value1IsNull = fcinfo.isnull;
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
|
|||
else
|
||||
newVal = FunctionCallInvoke(&fcinfo);
|
||||
if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
|
||||
pfree(peraggstate->value2);
|
||||
pfree(DatumGetPointer(peraggstate->value2));
|
||||
peraggstate->value2 = newVal;
|
||||
peraggstate->value2IsNull = fcinfo.isnull;
|
||||
}
|
||||
|
@ -424,12 +424,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
|
|||
if (OidIsValid(peraggstate->xfn1_oid) &&
|
||||
!peraggstate->value1IsNull &&
|
||||
!peraggstate->transtype1ByVal)
|
||||
pfree(peraggstate->value1);
|
||||
pfree(DatumGetPointer(peraggstate->value1));
|
||||
|
||||
if (OidIsValid(peraggstate->xfn2_oid) &&
|
||||
!peraggstate->value2IsNull &&
|
||||
!peraggstate->transtype2ByVal)
|
||||
pfree(peraggstate->value2);
|
||||
pfree(DatumGetPointer(peraggstate->value2));
|
||||
}
|
||||
|
||||
/* ---------------------------------------
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* $Id: nodeHash.c,v 1.47 2000/06/15 04:09:52 momjian Exp $
|
||||
* $Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* INTERFACE ROUTINES
|
||||
* ExecHash - generate an in-memory hash table of the relation
|
||||
* ExecInitHash - initialize node and subnodes..
|
||||
* ExecInitHash - initialize node and subnodes
|
||||
* ExecEndHash - shutdown node and subnodes
|
||||
*
|
||||
*/
|
||||
|
@ -23,11 +23,12 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "executor/execdebug.h"
|
||||
#include "executor/nodeHash.h"
|
||||
#include "executor/nodeHashjoin.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/portal.h"
|
||||
|
||||
|
||||
static int hashFunc(Datum key, int len, bool byVal);
|
||||
|
||||
|
@ -235,8 +236,6 @@ ExecHashTableCreate(Hash *node)
|
|||
int totalbuckets;
|
||||
int bucketsize;
|
||||
int i;
|
||||
Portal myPortal;
|
||||
char myPortalName[64];
|
||||
MemoryContext oldcxt;
|
||||
|
||||
/* ----------------
|
||||
|
@ -348,23 +347,21 @@ ExecHashTableCreate(Hash *node)
|
|||
hashtable->outerBatchSize = NULL;
|
||||
|
||||
/* ----------------
|
||||
* Create a named portal in which to keep the hashtable working storage.
|
||||
* Each hashjoin must have its own portal, so be wary of name conflicts.
|
||||
* Create temporary memory contexts in which to keep the hashtable
|
||||
* working storage. See notes in executor/hashjoin.h.
|
||||
* ----------------
|
||||
*/
|
||||
i = 0;
|
||||
do
|
||||
{
|
||||
i++;
|
||||
sprintf(myPortalName, "<hashtable %d>", i);
|
||||
myPortal = GetPortalByName(myPortalName);
|
||||
} while (PortalIsValid(myPortal));
|
||||
myPortal = CreatePortal(myPortalName);
|
||||
Assert(PortalIsValid(myPortal));
|
||||
hashtable->myPortal = (void *) myPortal; /* kluge for circular
|
||||
* includes */
|
||||
hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
|
||||
hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
|
||||
hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
|
||||
"HashTableContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
|
||||
"HashBatchContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
/* Allocate data that will live for the life of the hashjoin */
|
||||
|
||||
|
@ -395,11 +392,10 @@ ExecHashTableCreate(Hash *node)
|
|||
}
|
||||
|
||||
/*
|
||||
* Prepare portal for the first-scan space allocations; allocate the
|
||||
* Prepare context for the first-scan space allocations; allocate the
|
||||
* hashbucket array therein, and set each bucket "empty".
|
||||
*/
|
||||
MemoryContextSwitchTo(hashtable->batchCxt);
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
|
||||
hashtable->buckets = (HashJoinTuple *)
|
||||
palloc(nbuckets * sizeof(HashJoinTuple));
|
||||
|
@ -435,9 +431,8 @@ ExecHashTableDestroy(HashJoinTable hashtable)
|
|||
BufFileClose(hashtable->outerBatchFile[i]);
|
||||
}
|
||||
|
||||
/* Destroy the portal to release all working memory */
|
||||
/* cast here is a kluge for circular includes... */
|
||||
PortalDrop((Portal *) &hashtable->myPortal);
|
||||
/* Release working memory (batchCxt is a child, so it goes away too) */
|
||||
MemoryContextDelete(hashtable->hashCxt);
|
||||
|
||||
/* And drop the control block */
|
||||
pfree(hashtable);
|
||||
|
@ -676,11 +671,10 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
|||
|
||||
/*
|
||||
* Release all the hash buckets and tuples acquired in the prior pass,
|
||||
* and reinitialize the portal for a new pass.
|
||||
* and reinitialize the context for a new pass.
|
||||
*/
|
||||
MemoryContextReset(hashtable->batchCxt);
|
||||
oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
|
||||
EndPortalAllocMode();
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
|
||||
/*
|
||||
* We still use the same number of physical buckets as in the first
|
||||
|
|
|
@ -3,21 +3,20 @@
|
|||
* spi.c
|
||||
* Server Programming Interface
|
||||
*
|
||||
* $Id: spi.c,v 1.46 2000/05/30 04:24:45 tgl Exp $
|
||||
* $Id: spi.c,v 1.47 2000/06/28 03:31:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "executor/spi_priv.h"
|
||||
#include "access/printtup.h"
|
||||
|
||||
static Portal _SPI_portal = (Portal) NULL;
|
||||
static _SPI_connection *_SPI_stack = NULL;
|
||||
static _SPI_connection *_SPI_current = NULL;
|
||||
static int _SPI_connected = -1;
|
||||
static int _SPI_curid = -1;
|
||||
|
||||
DLLIMPORT uint32 SPI_processed = 0;
|
||||
DLLIMPORT SPITupleTable *SPI_tuptable;
|
||||
DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
|
||||
DLLIMPORT int SPI_result;
|
||||
|
||||
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
||||
|
@ -46,28 +45,6 @@ extern void ShowUsage(void);
|
|||
int
|
||||
SPI_connect()
|
||||
{
|
||||
char pname[64];
|
||||
PortalVariableMemory pvmem;
|
||||
|
||||
/*
|
||||
* It's possible on startup and after commit/abort. In future we'll
|
||||
* catch commit/abort in some way...
|
||||
*/
|
||||
strcpy(pname, "<SPI manager>");
|
||||
_SPI_portal = GetPortalByName(pname);
|
||||
if (!PortalIsValid(_SPI_portal))
|
||||
{
|
||||
if (_SPI_stack != NULL) /* there was abort */
|
||||
free(_SPI_stack);
|
||||
_SPI_current = _SPI_stack = NULL;
|
||||
_SPI_connected = _SPI_curid = -1;
|
||||
SPI_processed = 0;
|
||||
SPI_tuptable = NULL;
|
||||
_SPI_portal = CreatePortal(pname);
|
||||
if (!PortalIsValid(_SPI_portal))
|
||||
elog(FATAL, "SPI_connect: global initialization failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* When procedure called by Executor _SPI_curid expected to be equal
|
||||
* to _SPI_connected
|
||||
|
@ -99,15 +76,19 @@ SPI_connect()
|
|||
_SPI_current->processed = 0;
|
||||
_SPI_current->tuptable = NULL;
|
||||
|
||||
/* Create Portal for this procedure ... */
|
||||
snprintf(pname, 64, "<SPI %d>", _SPI_connected);
|
||||
_SPI_current->portal = CreatePortal(pname);
|
||||
if (!PortalIsValid(_SPI_current->portal))
|
||||
elog(FATAL, "SPI_connect: initialization failed");
|
||||
|
||||
/* ... and switch to Portal' Variable memory - procedure' context */
|
||||
pvmem = PortalGetVariableMemory(_SPI_current->portal);
|
||||
_SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
|
||||
/* Create memory contexts for this procedure */
|
||||
_SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
|
||||
"SPI Proc",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
_SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
|
||||
"SPI Exec",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
/* ... and switch to procedure's context */
|
||||
_SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
|
||||
|
||||
_SPI_current->savedId = GetScanCommandId();
|
||||
SetScanCommandId(GetCurrentCommandId());
|
||||
|
@ -127,7 +108,10 @@ SPI_finish()
|
|||
|
||||
/* Restore memory context as it was before procedure call */
|
||||
MemoryContextSwitchTo(_SPI_current->savedcxt);
|
||||
PortalDrop(&(_SPI_current->portal));
|
||||
|
||||
/* Release memory used in procedure call */
|
||||
MemoryContextDelete(_SPI_current->execCxt);
|
||||
MemoryContextDelete(_SPI_current->procCxt);
|
||||
|
||||
SetScanCommandId(_SPI_current->savedId);
|
||||
|
||||
|
@ -142,6 +126,7 @@ SPI_finish()
|
|||
{
|
||||
free(_SPI_stack);
|
||||
_SPI_stack = NULL;
|
||||
_SPI_current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -154,6 +139,25 @@ SPI_finish()
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up SPI state at transaction commit or abort (we don't care which).
|
||||
*/
|
||||
void
|
||||
AtEOXact_SPI(void)
|
||||
{
|
||||
/*
|
||||
* Note that memory contexts belonging to SPI stack entries will be
|
||||
* freed automatically, so we can ignore them here. We just need to
|
||||
* restore our static variables to initial state.
|
||||
*/
|
||||
if (_SPI_stack != NULL) /* there was abort */
|
||||
free(_SPI_stack);
|
||||
_SPI_current = _SPI_stack = NULL;
|
||||
_SPI_connected = _SPI_curid = -1;
|
||||
SPI_processed = 0;
|
||||
SPI_tuptable = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
SPI_push(void)
|
||||
{
|
||||
|
@ -508,61 +512,22 @@ SPI_palloc(Size size)
|
|||
void *
|
||||
SPI_repalloc(void *pointer, Size size)
|
||||
{
|
||||
MemoryContext oldcxt = NULL;
|
||||
|
||||
if (_SPI_curid + 1 == _SPI_connected) /* connected */
|
||||
{
|
||||
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
|
||||
elog(FATAL, "SPI: stack corrupted");
|
||||
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
|
||||
}
|
||||
|
||||
pointer = repalloc(pointer, size);
|
||||
|
||||
if (oldcxt)
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
return pointer;
|
||||
/* No longer need to worry which context chunk was in... */
|
||||
return repalloc(pointer, size);
|
||||
}
|
||||
|
||||
void
|
||||
SPI_pfree(void *pointer)
|
||||
{
|
||||
MemoryContext oldcxt = NULL;
|
||||
|
||||
if (_SPI_curid + 1 == _SPI_connected) /* connected */
|
||||
{
|
||||
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
|
||||
elog(FATAL, "SPI: stack corrupted");
|
||||
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
|
||||
}
|
||||
|
||||
/* No longer need to worry which context chunk was in... */
|
||||
pfree(pointer);
|
||||
|
||||
if (oldcxt)
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SPI_freetuple(HeapTuple tuple)
|
||||
{
|
||||
MemoryContext oldcxt = NULL;
|
||||
|
||||
if (_SPI_curid + 1 == _SPI_connected) /* connected */
|
||||
{
|
||||
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
|
||||
elog(FATAL, "SPI: stack corrupted");
|
||||
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
|
||||
}
|
||||
|
||||
/* No longer need to worry which context tuple was in... */
|
||||
heap_freetuple(tuple);
|
||||
|
||||
if (oldcxt)
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* =================== private functions =================== */
|
||||
|
@ -647,7 +612,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||
argtypes = plan->argtypes;
|
||||
}
|
||||
|
||||
queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs, FALSE);
|
||||
queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
|
||||
|
||||
_SPI_current->qtlist = queryTree_list;
|
||||
|
||||
|
@ -790,7 +755,6 @@ static int
|
|||
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
{
|
||||
Query *parseTree = queryDesc->parsetree;
|
||||
Plan *plan = queryDesc->plantree;
|
||||
int operation = queryDesc->operation;
|
||||
CommandDest dest = queryDesc->dest;
|
||||
TupleDesc tupdesc;
|
||||
|
@ -875,16 +839,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||
#endif
|
||||
tupdesc = ExecutorStart(queryDesc, state);
|
||||
|
||||
/* Don't work currently */
|
||||
/* Don't work currently --- need to rearrange callers so that
|
||||
* we prepare the portal before doing CreateExecutorState() etc.
|
||||
* See pquery.c for the correct order of operations.
|
||||
*/
|
||||
if (isRetrieveIntoPortal)
|
||||
{
|
||||
ProcessPortal(intoName,
|
||||
parseTree,
|
||||
plan,
|
||||
state,
|
||||
tupdesc,
|
||||
None);
|
||||
return SPI_OK_CURSOR;
|
||||
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
||||
}
|
||||
|
||||
ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
|
||||
|
@ -920,27 +881,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||
static MemoryContext
|
||||
_SPI_execmem()
|
||||
{
|
||||
MemoryContext oldcxt;
|
||||
PortalHeapMemory phmem;
|
||||
|
||||
phmem = PortalGetHeapMemory(_SPI_current->portal);
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
|
||||
|
||||
return oldcxt;
|
||||
|
||||
return MemoryContextSwitchTo(_SPI_current->execCxt);
|
||||
}
|
||||
|
||||
static MemoryContext
|
||||
_SPI_procmem()
|
||||
{
|
||||
MemoryContext oldcxt;
|
||||
PortalVariableMemory pvmem;
|
||||
|
||||
pvmem = PortalGetVariableMemory(_SPI_current->portal);
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
|
||||
|
||||
return oldcxt;
|
||||
|
||||
return MemoryContextSwitchTo(_SPI_current->procCxt);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -959,7 +906,6 @@ _SPI_begin_call(bool execmem)
|
|||
if (execmem) /* switch to the Executor memory context */
|
||||
{
|
||||
_SPI_execmem();
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -977,9 +923,10 @@ _SPI_end_call(bool procmem)
|
|||
_SPI_current->qtlist = NULL;
|
||||
|
||||
if (procmem) /* switch to the procedure memory context */
|
||||
{ /* but free Executor memory before */
|
||||
EndPortalAllocMode();
|
||||
{
|
||||
_SPI_procmem();
|
||||
/* and free Executor memory */
|
||||
MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1016,8 +963,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
|
|||
MemoryContext oldcxt = NULL;
|
||||
|
||||
if (location == _SPI_CPLAN_PROCXT)
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext)
|
||||
PortalGetVariableMemory(_SPI_current->portal));
|
||||
oldcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
|
||||
else if (location == _SPI_CPLAN_TOPCXT)
|
||||
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
|
@ -1033,7 +979,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
|
|||
else
|
||||
newplan->argtypes = NULL;
|
||||
|
||||
if (location != _SPI_CPLAN_CURCXT)
|
||||
if (oldcxt != NULL)
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
return newplan;
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
# Makefile for lib (miscellaneous stuff)
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.13 2000/05/29 05:44:45 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.14 2000/06/28 03:31:34 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SRCDIR = ../..
|
||||
include ../../Makefile.global
|
||||
|
||||
OBJS = bit.o fstack.o hasht.o lispsort.o stringinfo.o dllist.o
|
||||
OBJS = bit.o hasht.o lispsort.o stringinfo.o dllist.o
|
||||
|
||||
all: SUBSYS.o
|
||||
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* fstack.c
|
||||
* Fixed format stack definitions.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.14 2000/01/26 05:56:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
#include "lib/fstack.h"
|
||||
|
||||
/*
|
||||
* Internal function definitions
|
||||
*/
|
||||
|
||||
/*
|
||||
* FixedItemIsValid
|
||||
* True iff item is valid.
|
||||
*/
|
||||
#define FixedItemIsValid(item) PointerIsValid(item)
|
||||
|
||||
/*
|
||||
* FixedStackGetItemBase
|
||||
* Returns base of enclosing structure.
|
||||
*/
|
||||
#define FixedStackGetItemBase(stack, item) \
|
||||
((Pointer)((char *)(item) - (stack)->offset))
|
||||
|
||||
/*
|
||||
* FixedStackGetItem
|
||||
* Returns item of given pointer to enclosing structure.
|
||||
*/
|
||||
#define FixedStackGetItem(stack, pointer) \
|
||||
((FixedItem)((char *)(pointer) + (stack)->offset))
|
||||
|
||||
#define FixedStackIsValid(stack) ((bool)PointerIsValid(stack))
|
||||
|
||||
/*
|
||||
* External functions
|
||||
*/
|
||||
|
||||
void
|
||||
FixedStackInit(FixedStack stack, Offset offset)
|
||||
{
|
||||
AssertArg(PointerIsValid(stack));
|
||||
|
||||
stack->top = NULL;
|
||||
stack->offset = offset;
|
||||
}
|
||||
|
||||
Pointer
|
||||
FixedStackPop(FixedStack stack)
|
||||
{
|
||||
Pointer pointer;
|
||||
|
||||
AssertArg(FixedStackIsValid(stack));
|
||||
|
||||
if (!PointerIsValid(stack->top))
|
||||
return NULL;
|
||||
|
||||
pointer = FixedStackGetItemBase(stack, stack->top);
|
||||
stack->top = stack->top->next;
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
void
|
||||
FixedStackPush(FixedStack stack, Pointer pointer)
|
||||
{
|
||||
FixedItem item = FixedStackGetItem(stack, pointer);
|
||||
|
||||
AssertArg(FixedStackIsValid(stack));
|
||||
AssertArg(PointerIsValid(pointer));
|
||||
|
||||
item->next = stack->top;
|
||||
stack->top = item;
|
||||
}
|
||||
|
||||
#ifdef USE_ASSERT_CHECKING
|
||||
/*
|
||||
* FixedStackContains
|
||||
* True iff ordered stack contains given element.
|
||||
*
|
||||
* Note:
|
||||
* This is inefficient. It is intended for debugging use only.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if stack is invalid.
|
||||
* BadArg if pointer is invalid.
|
||||
*/
|
||||
static bool
|
||||
FixedStackContains(FixedStack stack, Pointer pointer)
|
||||
{
|
||||
FixedItem next;
|
||||
FixedItem item;
|
||||
|
||||
AssertArg(FixedStackIsValid(stack));
|
||||
AssertArg(PointerIsValid(pointer));
|
||||
|
||||
item = FixedStackGetItem(stack, pointer);
|
||||
|
||||
for (next = stack->top; FixedItemIsValid(next); next = next->next)
|
||||
{
|
||||
if (next == item)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Pointer
|
||||
FixedStackGetTop(FixedStack stack)
|
||||
{
|
||||
AssertArg(FixedStackIsValid(stack));
|
||||
|
||||
if (!PointerIsValid(stack->top))
|
||||
return NULL;
|
||||
|
||||
return FixedStackGetItemBase(stack, stack->top);
|
||||
}
|
||||
|
||||
Pointer
|
||||
FixedStackGetNext(FixedStack stack, Pointer pointer)
|
||||
{
|
||||
FixedItem item;
|
||||
|
||||
/* AssertArg(FixedStackIsValid(stack)); */
|
||||
/* AssertArg(PointerIsValid(pointer)); */
|
||||
AssertArg(FixedStackContains(stack, pointer));
|
||||
|
||||
item = FixedStackGetItem(stack, pointer)->next;
|
||||
|
||||
if (!PointerIsValid(item))
|
||||
return NULL;
|
||||
|
||||
return FixedStackGetItemBase(stack, item);
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: stringinfo.c,v 1.25 2000/04/12 17:15:11 momjian Exp $
|
||||
* $Id: stringinfo.c,v 1.26 2000/06/28 03:31:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -29,8 +29,6 @@ makeStringInfo(void)
|
|||
StringInfo res;
|
||||
|
||||
res = (StringInfo) palloc(sizeof(StringInfoData));
|
||||
if (res == NULL)
|
||||
elog(ERROR, "makeStringInfo: Out of memory");
|
||||
|
||||
initStringInfo(res);
|
||||
|
||||
|
@ -49,9 +47,6 @@ initStringInfo(StringInfo str)
|
|||
int size = 256; /* initial default buffer size */
|
||||
|
||||
str->data = (char *) palloc(size);
|
||||
if (str->data == NULL)
|
||||
elog(ERROR,
|
||||
"initStringInfo: Out of memory (%d bytes requested)", size);
|
||||
str->maxlen = size;
|
||||
str->len = 0;
|
||||
str->data[0] = '\0';
|
||||
|
@ -62,6 +57,11 @@ initStringInfo(StringInfo str)
|
|||
*
|
||||
* Internal routine: make sure there is enough space for 'needed' more bytes
|
||||
* ('needed' does not include the terminating null).
|
||||
*
|
||||
* NB: because we use repalloc() to enlarge the buffer, the string buffer
|
||||
* will remain allocated in the same memory context that was current when
|
||||
* initStringInfo was called, even if another context is now current.
|
||||
* This is the desired and indeed critical behavior!
|
||||
*/
|
||||
static void
|
||||
enlargeStringInfo(StringInfo str, int needed)
|
||||
|
@ -83,9 +83,6 @@ enlargeStringInfo(StringInfo str, int needed)
|
|||
newlen = 2 * newlen;
|
||||
|
||||
str->data = (char *) repalloc(str->data, newlen);
|
||||
if (str->data == NULL)
|
||||
elog(ERROR,
|
||||
"enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
|
||||
|
||||
str->maxlen = newlen;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.46 2000/06/09 01:11:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.47 2000/06/28 03:31:41 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This should be moved to a more appropriate place. It is here
|
||||
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* Builtin functions for open/close/read/write operations on large objects.
|
||||
*
|
||||
* These functions operate in a private GlobalMemoryContext, which means
|
||||
* These functions operate in a private MemoryContext, which means
|
||||
* that large object descriptors hang around until we destroy the context.
|
||||
* That happens in lo_commit(). It'd be possible to prolong the lifetime
|
||||
* of the context so that LO FDs are good across transactions (for example,
|
||||
|
@ -24,8 +24,10 @@
|
|||
* But we'd need additional state in order to do the right thing at the
|
||||
* end of an aborted transaction. FDs opened during an aborted xact would
|
||||
* still need to be closed, since they might not be pointing at valid
|
||||
* relations at all. For now, we'll stick with the existing documented
|
||||
* semantics of LO FDs: they're only good within a transaction.
|
||||
* relations at all. Locking semantics are also an interesting problem
|
||||
* if LOs stay open across transactions. For now, we'll stick with the
|
||||
* existing documented semantics of LO FDs: they're only good within a
|
||||
* transaction.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -56,7 +58,7 @@
|
|||
*/
|
||||
static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
|
||||
|
||||
static GlobalMemory fscxt = NULL;
|
||||
static MemoryContext fscxt = NULL;
|
||||
|
||||
|
||||
static int newLOfd(LargeObjectDesc *lobjCookie);
|
||||
|
@ -80,8 +82,13 @@ lo_open(PG_FUNCTION_ARGS)
|
|||
#endif
|
||||
|
||||
if (fscxt == NULL)
|
||||
fscxt = CreateGlobalMemory("Filesystem");
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
fscxt = AllocSetContextCreate(TopMemoryContext,
|
||||
"Filesystem",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
lobjDesc = inv_open(lobjId, mode);
|
||||
|
||||
|
@ -128,7 +135,7 @@ lo_close(PG_FUNCTION_ARGS)
|
|||
#endif
|
||||
|
||||
Assert(fscxt != NULL);
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
inv_close(cookies[fd]);
|
||||
|
||||
|
@ -166,7 +173,7 @@ lo_read(int fd, char *buf, int len)
|
|||
}
|
||||
|
||||
Assert(fscxt != NULL);
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
status = inv_read(cookies[fd], buf, len);
|
||||
|
||||
|
@ -193,7 +200,7 @@ lo_write(int fd, char *buf, int len)
|
|||
}
|
||||
|
||||
Assert(fscxt != NULL);
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
status = inv_write(cookies[fd], buf, len);
|
||||
|
||||
|
@ -224,7 +231,7 @@ lo_lseek(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
Assert(fscxt != NULL);
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
status = inv_seek(cookies[fd], offset, whence);
|
||||
|
||||
|
@ -242,9 +249,13 @@ lo_creat(PG_FUNCTION_ARGS)
|
|||
Oid lobjId;
|
||||
|
||||
if (fscxt == NULL)
|
||||
fscxt = CreateGlobalMemory("Filesystem");
|
||||
fscxt = AllocSetContextCreate(TopMemoryContext,
|
||||
"Filesystem",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
lobjDesc = inv_create(mode);
|
||||
|
||||
|
@ -493,7 +504,7 @@ lo_commit(bool isCommit)
|
|||
if (fscxt == NULL)
|
||||
return; /* no LO operations in this xact */
|
||||
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
||||
currentContext = MemoryContextSwitchTo(fscxt);
|
||||
|
||||
/*
|
||||
* Clean out still-open index scans (not necessary if aborting) and
|
||||
|
@ -512,7 +523,7 @@ lo_commit(bool isCommit)
|
|||
MemoryContextSwitchTo(currentContext);
|
||||
|
||||
/* Release the LO memory context to prevent permanent memory leaks. */
|
||||
GlobalMemoryDestroy(fscxt);
|
||||
MemoryContextDelete(fscxt);
|
||||
fscxt = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.32 2000/05/28 17:55:56 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.33 2000/06/28 03:31:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -135,9 +135,11 @@ PQexec(char *query)
|
|||
/* ----------------
|
||||
* pg_exec_query_dest will put the query results in a portal which will
|
||||
* end up on the top of the portal stack.
|
||||
*
|
||||
* XXX memory context manipulation needs thought here.
|
||||
* ----------------
|
||||
*/
|
||||
pg_exec_query_dest(query, Local, FALSE);
|
||||
pg_exec_query_dest(query, Local, CurrentMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* pop the portal off the portal stack and return the
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.15 2000/06/11 11:39:50 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.16 2000/06/28 03:31:41 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This shouldn't be in libpq, but the monitor and some other
|
||||
|
@ -44,6 +44,44 @@
|
|||
|
||||
#include "libpq/pqsignal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Initialize BlockSig and UnBlockSig.
|
||||
*
|
||||
* BlockSig is the set of signals to block when we are trying to block
|
||||
* signals. This includes all signals we normally expect to get, but NOT
|
||||
* signals that should never be turned off.
|
||||
*
|
||||
* UnBlockSig is the set of signals to block when we don't want to block
|
||||
* signals (is this ever nonzero??)
|
||||
*/
|
||||
void
|
||||
pqinitmask(void)
|
||||
{
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigemptyset(&UnBlockSig);
|
||||
sigfillset(&BlockSig);
|
||||
sigdelset(&BlockSig, SIGABRT);
|
||||
sigdelset(&BlockSig, SIGILL);
|
||||
sigdelset(&BlockSig, SIGSEGV);
|
||||
sigdelset(&BlockSig, SIGBUS);
|
||||
sigdelset(&BlockSig, SIGTRAP);
|
||||
sigdelset(&BlockSig, SIGCONT);
|
||||
sigdelset(&BlockSig, SIGSYS);
|
||||
#else
|
||||
UnBlockSig = 0;
|
||||
BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) |
|
||||
sigmask(SIGTERM) | sigmask(SIGALRM) |
|
||||
sigmask(SIGINT) | sigmask(SIGUSR1) |
|
||||
sigmask(SIGUSR2) | sigmask(SIGCHLD) |
|
||||
sigmask(SIGWINCH) | sigmask(SIGFPE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set up a signal handler
|
||||
*/
|
||||
pqsigfunc
|
||||
pqsignal(int signo, pqsigfunc func)
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: geqo_eval.c,v 1.50 2000/05/30 00:49:46 momjian Exp $
|
||||
* $Id: geqo_eval.c,v 1.51 2000/06/28 03:31:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -19,9 +19,9 @@
|
|||
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include <math.h>
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#else
|
||||
|
@ -33,42 +33,9 @@
|
|||
#include "optimizer/geqo.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/paths.h"
|
||||
#include "utils/portal.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
|
||||
/*
|
||||
* Variables set by geqo_eval_startup for use within a single GEQO run
|
||||
*/
|
||||
static MemoryContext geqo_eval_context;
|
||||
|
||||
/*
|
||||
* geqo_eval_startup:
|
||||
* Must be called during geqo_main startup (before geqo_eval may be called)
|
||||
*
|
||||
* The main thing we need to do here is prepare a private memory context for
|
||||
* allocation of temp storage used while constructing a path in geqo_eval().
|
||||
* Since geqo_eval() will be called many times, we can't afford to let all
|
||||
* that memory go unreclaimed until end of statement. We use a special
|
||||
* named portal to hold the context, so that it will be freed even if
|
||||
* we abort via elog(ERROR). The working data is allocated in the portal's
|
||||
* heap memory context.
|
||||
*/
|
||||
void
|
||||
geqo_eval_startup(void)
|
||||
{
|
||||
#define GEQO_PORTAL_NAME "<geqo workspace>"
|
||||
Portal geqo_portal = GetPortalByName(GEQO_PORTAL_NAME);
|
||||
|
||||
if (!PortalIsValid(geqo_portal))
|
||||
{
|
||||
/* First time through (within current transaction, that is) */
|
||||
geqo_portal = CreatePortal(GEQO_PORTAL_NAME);
|
||||
Assert(PortalIsValid(geqo_portal));
|
||||
}
|
||||
|
||||
geqo_eval_context = (MemoryContext) PortalGetHeapMemory(geqo_portal);
|
||||
}
|
||||
|
||||
/*
|
||||
* geqo_eval
|
||||
*
|
||||
|
@ -77,21 +44,31 @@ geqo_eval_startup(void)
|
|||
Cost
|
||||
geqo_eval(Query *root, Gene *tour, int num_gene)
|
||||
{
|
||||
MemoryContext mycontext;
|
||||
MemoryContext oldcxt;
|
||||
RelOptInfo *joinrel;
|
||||
Cost fitness;
|
||||
List *savelist;
|
||||
|
||||
/*
|
||||
* Create a private memory context that will hold all temp storage
|
||||
* allocated inside gimme_tree().
|
||||
*
|
||||
* Since geqo_eval() will be called many times, we can't afford to let
|
||||
* all that memory go unreclaimed until end of statement. Note we make
|
||||
* the temp context a child of TransactionCommandContext, so that
|
||||
* it will be freed even if we abort via elog(ERROR).
|
||||
*/
|
||||
mycontext = AllocSetContextCreate(TransactionCommandContext,
|
||||
"GEQO",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
oldcxt = MemoryContextSwitchTo(mycontext);
|
||||
|
||||
/* preserve root->join_rel_list, which gimme_tree changes */
|
||||
savelist = root->join_rel_list;
|
||||
|
||||
/*
|
||||
* create a temporary allocation context for the path construction
|
||||
* work
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo(geqo_eval_context);
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
|
||||
/* construct the best path for the given combination of relations */
|
||||
joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
|
||||
|
||||
|
@ -107,8 +84,8 @@ geqo_eval(Query *root, Gene *tour, int num_gene)
|
|||
root->join_rel_list = savelist;
|
||||
|
||||
/* release all the memory acquired within gimme_tree */
|
||||
EndPortalAllocMode();
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
MemoryContextDelete(mycontext);
|
||||
|
||||
return fitness;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: geqo_main.c,v 1.21 2000/05/31 00:28:19 petere Exp $
|
||||
* $Id: geqo_main.c,v 1.22 2000/06/28 03:31:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -110,9 +110,6 @@ geqo(Query *root)
|
|||
else
|
||||
srandom(time(NULL));
|
||||
|
||||
/* initialize plan evaluator */
|
||||
geqo_eval_startup();
|
||||
|
||||
/* allocate genetic pool memory */
|
||||
pool = alloc_pool(pool_size, number_of_rels);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.149 2000/06/22 22:31:20 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.150 2000/06/28 03:31:52 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
|
@ -378,15 +378,38 @@ PostmasterMain(int argc, char *argv[])
|
|||
*/
|
||||
umask((mode_t) 0077);
|
||||
|
||||
ResetAllOptions();
|
||||
|
||||
MyProcPid = getpid();
|
||||
|
||||
/*
|
||||
* Fire up essential subsystems: error and memory management
|
||||
*/
|
||||
EnableExceptionHandling(true);
|
||||
MemoryContextInit();
|
||||
|
||||
/*
|
||||
* By default, palloc() requests in the postmaster will be allocated
|
||||
* in the PostmasterContext, which is space that can be recycled by
|
||||
* backends. Allocated data that needs to be available to backends
|
||||
* should be allocated in TopMemoryContext.
|
||||
*/
|
||||
PostmasterContext = AllocSetContextCreate(TopMemoryContext,
|
||||
"Postmaster",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
MemoryContextSwitchTo(PostmasterContext);
|
||||
|
||||
/*
|
||||
* Options setup
|
||||
*/
|
||||
if (getenv("PGDATA"))
|
||||
DataDir = strdup(getenv("PGDATA")); /* default value */
|
||||
|
||||
if (getenv("PGPORT"))
|
||||
PostPortName = atoi(getenv("PGPORT"));
|
||||
|
||||
ResetAllOptions();
|
||||
|
||||
/*
|
||||
* First we must scan for a -D argument to get the data dir. Then
|
||||
* read the config file. Finally, scan all the other arguments.
|
||||
|
@ -600,7 +623,6 @@ PostmasterMain(int argc, char *argv[])
|
|||
}
|
||||
#endif
|
||||
/* set up shared memory and semaphores */
|
||||
EnableMemoryContext(TRUE);
|
||||
reset_shared(PostPortName);
|
||||
|
||||
/*
|
||||
|
@ -662,7 +684,7 @@ PostmasterMain(int argc, char *argv[])
|
|||
/*
|
||||
* Set up signal handlers for the postmaster process.
|
||||
*/
|
||||
PG_INITMASK();
|
||||
pqinitmask();
|
||||
PG_SETMASK(&BlockSig);
|
||||
|
||||
pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have children do same */
|
||||
|
@ -1867,6 +1889,7 @@ DoBackend(Port *port)
|
|||
/* Save port etc. for ps status */
|
||||
MyProcPort = port;
|
||||
|
||||
/* Reset MyProcPid to new backend's pid */
|
||||
MyProcPid = getpid();
|
||||
|
||||
/*
|
||||
|
@ -1946,6 +1969,19 @@ DoBackend(Port *port)
|
|||
|
||||
av[ac] = (char *) NULL;
|
||||
|
||||
/*
|
||||
* Release postmaster's working memory context so that backend can
|
||||
* recycle the space. Note we couldn't do it earlier than here,
|
||||
* because port pointer is pointing into that space! But now we
|
||||
* have copied all the interesting info into safe local storage.
|
||||
*/
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
PostmasterContext = NULL;
|
||||
|
||||
/*
|
||||
* Debug: print arguments being passed to backend
|
||||
*/
|
||||
if (DebugLvl > 1)
|
||||
{
|
||||
fprintf(stderr, "%s child[%d]: starting with (",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.46 2000/06/15 04:09:58 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.47 2000/06/28 03:31:56 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -16,51 +16,20 @@
|
|||
#include "postgres.h"
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "parser/parse_relation.h"
|
||||
#include "rewrite/rewriteDefine.h"
|
||||
#include "rewrite/rewriteSupport.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
|
||||
Oid LastOidProcessed = InvalidOid;
|
||||
|
||||
|
||||
/*
|
||||
* Convert given string to a suitably quoted string constant,
|
||||
* and append it to the StringInfo buffer.
|
||||
* XXX Any MULTIBYTE considerations here?
|
||||
*/
|
||||
static void
|
||||
quoteString(StringInfo buf, char *source)
|
||||
{
|
||||
char *current;
|
||||
|
||||
appendStringInfoChar(buf, '\'');
|
||||
for (current = source; *current; current++)
|
||||
{
|
||||
char ch = *current;
|
||||
|
||||
if (ch == '\'' || ch == '\\')
|
||||
{
|
||||
appendStringInfoChar(buf, '\\');
|
||||
appendStringInfoChar(buf, ch);
|
||||
}
|
||||
else if (ch >= 0 && ch < ' ')
|
||||
appendStringInfo(buf, "\\%03o", (int) ch);
|
||||
else
|
||||
appendStringInfoChar(buf, ch);
|
||||
}
|
||||
appendStringInfoChar(buf, '\'');
|
||||
}
|
||||
|
||||
/*
|
||||
* InsertRule -
|
||||
* takes the arguments and inserts them as attributes into the system
|
||||
* relation "pg_rewrite"
|
||||
*
|
||||
* MODS : changes the value of LastOidProcessed as a side
|
||||
* effect of inserting the rule tuple
|
||||
*
|
||||
* ARGS : rulname - name of the rule
|
||||
* evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
|
||||
* evobj - name of relation
|
||||
|
@ -78,11 +47,17 @@ InsertRule(char *rulname,
|
|||
bool evinstead,
|
||||
char *actiontree)
|
||||
{
|
||||
StringInfoData rulebuf;
|
||||
Relation eventrel;
|
||||
Oid eventrel_oid;
|
||||
AttrNumber evslot_index;
|
||||
char *is_instead = "f";
|
||||
int i;
|
||||
Datum values[Natts_pg_rewrite];
|
||||
char nulls[Natts_pg_rewrite];
|
||||
NameData rname;
|
||||
Relation pg_rewrite_desc;
|
||||
TupleDesc tupDesc;
|
||||
HeapTuple tup;
|
||||
Oid rewriteObjectId;
|
||||
|
||||
eventrel = heap_openr(evobj, AccessShareLock);
|
||||
eventrel_oid = RelationGetRelid(eventrel);
|
||||
|
@ -96,9 +71,6 @@ InsertRule(char *rulname,
|
|||
evslot_index = attnameAttNum(eventrel, evslot);
|
||||
heap_close(eventrel, AccessShareLock);
|
||||
|
||||
if (evinstead)
|
||||
is_instead = "t";
|
||||
|
||||
if (evqual == NULL)
|
||||
evqual = "<>";
|
||||
|
||||
|
@ -106,23 +78,54 @@ InsertRule(char *rulname,
|
|||
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
|
||||
rulname);
|
||||
|
||||
initStringInfo(&rulebuf);
|
||||
appendStringInfo(&rulebuf,
|
||||
"INSERT INTO pg_rewrite (rulename, ev_type, ev_class, ev_attr, ev_action, ev_qual, is_instead) VALUES (");
|
||||
quoteString(&rulebuf, rulname);
|
||||
appendStringInfo(&rulebuf, ", %d::char, %u::oid, %d::int2, ",
|
||||
evtype, eventrel_oid, evslot_index);
|
||||
quoteString(&rulebuf, actiontree);
|
||||
appendStringInfo(&rulebuf, "::text, ");
|
||||
quoteString(&rulebuf, evqual);
|
||||
appendStringInfo(&rulebuf, "::text, '%s'::bool);",
|
||||
is_instead);
|
||||
/* ----------------
|
||||
* Set up *nulls and *values arrays
|
||||
* ----------------
|
||||
*/
|
||||
MemSet(nulls, ' ', sizeof(nulls));
|
||||
|
||||
pg_exec_query_dest(rulebuf.data, None, true);
|
||||
i = 0;
|
||||
namestrcpy(&rname, rulname);
|
||||
values[i++] = NameGetDatum(&rname);
|
||||
values[i++] = CharGetDatum(evtype + '0');
|
||||
values[i++] = ObjectIdGetDatum(eventrel_oid);
|
||||
values[i++] = Int16GetDatum(evslot_index);
|
||||
values[i++] = BoolGetDatum(evinstead);
|
||||
values[i++] = PointerGetDatum(lztextin(evqual));
|
||||
values[i++] = PointerGetDatum(lztextin(actiontree));
|
||||
|
||||
pfree(rulebuf.data);
|
||||
/* ----------------
|
||||
* create a new pg_rewrite tuple
|
||||
* ----------------
|
||||
*/
|
||||
pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
|
||||
|
||||
return LastOidProcessed;
|
||||
tupDesc = pg_rewrite_desc->rd_att;
|
||||
|
||||
tup = heap_formtuple(tupDesc,
|
||||
values,
|
||||
nulls);
|
||||
|
||||
heap_insert(pg_rewrite_desc, tup);
|
||||
|
||||
rewriteObjectId = tup->t_data->t_oid;
|
||||
|
||||
if (RelationGetForm(pg_rewrite_desc)->relhasindex)
|
||||
{
|
||||
Relation idescs[Num_pg_rewrite_indices];
|
||||
|
||||
CatalogOpenIndices(Num_pg_rewrite_indices, Name_pg_rewrite_indices,
|
||||
idescs);
|
||||
CatalogIndexInsert(idescs, Num_pg_rewrite_indices, pg_rewrite_desc,
|
||||
tup);
|
||||
CatalogCloseIndices(Num_pg_rewrite_indices, idescs);
|
||||
}
|
||||
|
||||
heap_freetuple(tup);
|
||||
|
||||
heap_close(pg_rewrite_desc, RowExclusiveLock);
|
||||
|
||||
return rewriteObjectId;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.41 2000/01/26 05:56:50 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.42 2000/06/28 03:31:56 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -136,7 +136,7 @@ prs2_addToRelation(Oid relid,
|
|||
* create an in memory RewriteRule data structure which is cached by
|
||||
* every Relation descriptor. (see utils/cache/relcache.c)
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
|
||||
if (qual != NULL)
|
||||
qual = copyObject(qual);
|
||||
|
@ -159,7 +159,7 @@ prs2_addToRelation(Oid relid,
|
|||
if (relation->rd_rules == NULL)
|
||||
{
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
rulelock = (RuleLock *) palloc(sizeof(RuleLock));
|
||||
rulelock->numLocks = 1;
|
||||
rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
|
||||
|
@ -181,7 +181,7 @@ prs2_addToRelation(Oid relid,
|
|||
rulelock = relation->rd_rules;
|
||||
numlock = rulelock->numLocks;
|
||||
/* expand, for safety reasons */
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
|
||||
sizeof(RewriteRule *) * (numlock + 1));
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
@ -212,7 +212,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
|
|||
break;
|
||||
}
|
||||
Assert(i < numlock);
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
pfree(rulelock->rules[i]);
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
if (numlock == 1)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.51 2000/05/30 00:49:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.52 2000/06/28 03:31:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -262,29 +262,23 @@ InitShmem(unsigned int key, unsigned int size)
|
|||
}
|
||||
|
||||
/*
|
||||
* ShmemAlloc -- allocate word-aligned byte string from
|
||||
* shared memory
|
||||
* ShmemAlloc -- allocate max-aligned byte string from shared memory
|
||||
*
|
||||
* Assumes ShmemLock and ShmemFreeStart are initialized.
|
||||
* Returns: real pointer to memory or NULL if we are out
|
||||
* of space. Has to return a real pointer in order
|
||||
* to be compatable with malloc().
|
||||
* to be compatible with malloc().
|
||||
*/
|
||||
long *
|
||||
ShmemAlloc(unsigned long size)
|
||||
void *
|
||||
ShmemAlloc(Size size)
|
||||
{
|
||||
unsigned long tmpFree;
|
||||
long *newSpace;
|
||||
void *newSpace;
|
||||
|
||||
/*
|
||||
* ensure space is word aligned.
|
||||
*
|
||||
* Word-alignment is not good enough. We have to be more conservative:
|
||||
* doubles need 8-byte alignment. (We probably only need this on RISC
|
||||
* platforms but this is not a big waste of space.) - ay 12/94
|
||||
* ensure all space is adequately aligned.
|
||||
*/
|
||||
if (size % sizeof(double))
|
||||
size += sizeof(double) - (size % sizeof(double));
|
||||
size = MAXALIGN(size);
|
||||
|
||||
Assert(*ShmemFreeStart);
|
||||
|
||||
|
@ -293,7 +287,7 @@ ShmemAlloc(unsigned long size)
|
|||
tmpFree = *ShmemFreeStart + size;
|
||||
if (tmpFree <= ShmemSize)
|
||||
{
|
||||
newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
|
||||
newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
|
||||
*ShmemFreeStart += size;
|
||||
}
|
||||
else
|
||||
|
@ -302,7 +296,8 @@ ShmemAlloc(unsigned long size)
|
|||
SpinRelease(ShmemLock);
|
||||
|
||||
if (!newSpace)
|
||||
elog(NOTICE, "ShmemAlloc: out of memory ");
|
||||
elog(NOTICE, "ShmemAlloc: out of memory");
|
||||
|
||||
return newSpace;
|
||||
}
|
||||
|
||||
|
@ -336,7 +331,7 @@ ShmemInitHash(char *name, /* table string name for shmem index */
|
|||
int hash_flags) /* info about infoP */
|
||||
{
|
||||
bool found;
|
||||
long *location;
|
||||
void *location;
|
||||
|
||||
/*
|
||||
* Hash tables allocated in shared memory have a fixed directory; it
|
||||
|
@ -478,12 +473,12 @@ ShmemPIDDestroy(int pid)
|
|||
* the object is already in the shmem index (hence, already
|
||||
* initialized).
|
||||
*/
|
||||
long *
|
||||
ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
|
||||
void *
|
||||
ShmemInitStruct(char *name, Size size, bool *foundPtr)
|
||||
{
|
||||
ShmemIndexEnt *result,
|
||||
item;
|
||||
long *structPtr;
|
||||
void *structPtr;
|
||||
|
||||
strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
|
||||
item.location = BAD_LOCATION;
|
||||
|
@ -498,27 +493,27 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
|
|||
#endif
|
||||
|
||||
/*
|
||||
* If the shmem index doesnt exist, we fake it.
|
||||
* If the shmem index doesn't exist, we fake it.
|
||||
*
|
||||
* If we are creating the first shmem index, then let shmemalloc()
|
||||
* allocate the space for a new HTAB. Otherwise, find the old one
|
||||
* and return that. Notice that the ShmemIndexLock is held until
|
||||
* the shmem index has been completely initialized.
|
||||
*/
|
||||
Assert(!strcmp(name, strname));
|
||||
Assert(strcmp(name, strname) == 0);
|
||||
if (ShmemBootstrap)
|
||||
{
|
||||
/* in POSTMASTER/Single process */
|
||||
|
||||
*foundPtr = FALSE;
|
||||
return (long *) ShmemAlloc(size);
|
||||
return ShmemAlloc(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(ShmemIndexOffset);
|
||||
|
||||
*foundPtr = TRUE;
|
||||
return (long *) MAKE_PTR(*ShmemIndexOffset);
|
||||
return (void *) MAKE_PTR(*ShmemIndexOffset);
|
||||
}
|
||||
|
||||
|
||||
|
@ -554,12 +549,12 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
|
|||
/* let caller print its message too */
|
||||
return NULL;
|
||||
}
|
||||
structPtr = (long *) MAKE_PTR(result->location);
|
||||
structPtr = (void *) MAKE_PTR(result->location);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It isn't in the table yet. allocate and initialize it */
|
||||
structPtr = ShmemAlloc((long) size);
|
||||
structPtr = ShmemAlloc(size);
|
||||
if (!structPtr)
|
||||
{
|
||||
/* out of memory */
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.71 2000/06/17 23:41:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.72 2000/06/28 03:32:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1090,7 +1090,7 @@ inv_newtuple(LargeObjectDesc *obj_desc,
|
|||
|
||||
ntup->t_len = tupsize;
|
||||
ItemPointerSet(&ntup->t_self, BufferGetBlockNumber(buffer), off);
|
||||
LastOidProcessed = ntup->t_data->t_oid = newoid();
|
||||
ntup->t_data->t_oid = newoid();
|
||||
TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_data->t_xmin));
|
||||
ntup->t_data->t_cmin = GetCurrentCommandId();
|
||||
StoreInvalidTransactionId(&(ntup->t_data->t_xmax));
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.69 2000/06/04 01:44:32 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.70 2000/06/28 03:32:07 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Outside modules can create a lock table and acquire/release
|
||||
|
@ -225,6 +225,11 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable,
|
|||
* has its name stored in the shmem index at its creation. It
|
||||
* is wasteful, in this case, but not much space is involved.
|
||||
*
|
||||
* NOTE: data structures allocated here are allocated permanently, using
|
||||
* TopMemoryContext and shared memory. We don't ever release them anyway,
|
||||
* and in normal multi-backend operation the lock table structures set up
|
||||
* by the postmaster are inherited by each backend, so they must be in
|
||||
* TopMemoryContext.
|
||||
*/
|
||||
LOCKMETHOD
|
||||
LockMethodTableInit(char *tabName,
|
||||
|
@ -246,22 +251,13 @@ LockMethodTableInit(char *tabName,
|
|||
return INVALID_LOCKMETHOD;
|
||||
}
|
||||
|
||||
/* allocate a string for the shmem index table lookup */
|
||||
shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32));
|
||||
if (!shmemName)
|
||||
{
|
||||
elog(NOTICE, "LockMethodTableInit: couldn't malloc string %s \n", tabName);
|
||||
return INVALID_LOCKMETHOD;
|
||||
}
|
||||
/* Allocate a string for the shmem index table lookups. */
|
||||
/* This is just temp space in this routine, so palloc is OK. */
|
||||
shmemName = (char *) palloc(strlen(tabName) + 32);
|
||||
|
||||
/* each lock table has a non-shared header */
|
||||
lockMethodTable = (LOCKMETHODTABLE *) palloc((unsigned) sizeof(LOCKMETHODTABLE));
|
||||
if (!lockMethodTable)
|
||||
{
|
||||
elog(NOTICE, "LockMethodTableInit: couldn't malloc lock table %s\n", tabName);
|
||||
pfree(shmemName);
|
||||
return INVALID_LOCKMETHOD;
|
||||
}
|
||||
/* each lock table has a non-shared, permanent header */
|
||||
lockMethodTable = (LOCKMETHODTABLE *)
|
||||
MemoryContextAlloc(TopMemoryContext, sizeof(LOCKMETHODTABLE));
|
||||
|
||||
/* ------------------------
|
||||
* find/acquire the spinlock for the table
|
||||
|
@ -269,7 +265,6 @@ LockMethodTableInit(char *tabName,
|
|||
*/
|
||||
SpinAcquire(LockMgrLock);
|
||||
|
||||
|
||||
/* -----------------------
|
||||
* allocate a control structure from shared memory or attach to it
|
||||
* if it already exists.
|
||||
|
@ -277,7 +272,7 @@ LockMethodTableInit(char *tabName,
|
|||
*/
|
||||
sprintf(shmemName, "%s (ctl)", tabName);
|
||||
lockMethodTable->ctl = (LOCKMETHODCTL *)
|
||||
ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found);
|
||||
ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
|
||||
|
||||
if (!lockMethodTable->ctl)
|
||||
{
|
||||
|
@ -910,7 +905,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
|
|||
LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode);
|
||||
|
||||
old_status = pstrdup(get_ps_display());
|
||||
new_status = palloc(strlen(get_ps_display()) + 10);
|
||||
new_status = (char *) palloc(strlen(get_ps_display()) + 10);
|
||||
strcpy(new_status, get_ps_display());
|
||||
strcat(new_status, " waiting");
|
||||
set_ps_display(new_status);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -47,7 +47,7 @@
|
|||
* This is so that we can support more backends. (system-wide semaphore
|
||||
* sets run out pretty fast.) -ay 4/95
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
@ -119,7 +119,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
|
|||
|
||||
/* attach to the free list */
|
||||
ProcGlobal = (PROC_HDR *)
|
||||
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
|
||||
ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
|
||||
|
||||
/* --------------------
|
||||
* We're the first - initialize.
|
||||
|
@ -185,7 +185,7 @@ InitProcess(IPCKey key)
|
|||
|
||||
/* attach to the free list */
|
||||
ProcGlobal = (PROC_HDR *)
|
||||
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
|
||||
ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
|
||||
if (!found)
|
||||
{
|
||||
/* this should not happen. InitProcGlobal() is called before this. */
|
||||
|
@ -218,7 +218,7 @@ InitProcess(IPCKey key)
|
|||
* cleanup dead processes).
|
||||
*/
|
||||
|
||||
MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
|
||||
MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
|
||||
if (!MyProc)
|
||||
{
|
||||
SpinRelease(ProcStructLock);
|
||||
|
@ -458,7 +458,7 @@ ProcQueueAlloc(char *name)
|
|||
{
|
||||
bool found;
|
||||
PROC_QUEUE *queue = (PROC_QUEUE *)
|
||||
ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
|
||||
ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
|
||||
|
||||
if (!queue)
|
||||
return NULL;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.71 2000/06/19 23:37:08 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.72 2000/06/28 03:32:14 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -94,19 +94,15 @@ static BlockNumber _mdnblocks(File file, Size blcksz);
|
|||
int
|
||||
mdinit()
|
||||
{
|
||||
MemoryContext oldcxt;
|
||||
int i;
|
||||
|
||||
MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
|
||||
if (MdCxt == (MemoryContext) NULL)
|
||||
return SM_FAIL;
|
||||
MdCxt = AllocSetContextCreate(TopMemoryContext,
|
||||
"MdSmgr",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||
Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
if (Md_fdvec == (MdfdVec *) NULL)
|
||||
return SM_FAIL;
|
||||
Md_fdvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
|
||||
|
||||
MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
|
||||
|
||||
|
@ -208,7 +204,6 @@ mdunlink(Relation reln)
|
|||
int nblocks;
|
||||
int fd;
|
||||
MdfdVec *v;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
/*
|
||||
* If the relation is already unlinked,we have nothing to do any more.
|
||||
|
@ -238,7 +233,6 @@ mdunlink(Relation reln)
|
|||
|
||||
Md_fdvec[fd].mdfd_flags = (uint16) 0;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||
#ifndef LET_OS_MANAGE_FILESIZE
|
||||
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
|
||||
{
|
||||
|
@ -256,7 +250,6 @@ mdunlink(Relation reln)
|
|||
FileTruncate(v->mdfd_vfd, 0);
|
||||
FileUnlink(v->mdfd_vfd);
|
||||
#endif
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
_fdvec_free(fd);
|
||||
|
||||
|
@ -400,9 +393,7 @@ static void
|
|||
mdclose_fd(int fd)
|
||||
{
|
||||
MdfdVec *v;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||
#ifndef LET_OS_MANAGE_FILESIZE
|
||||
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
|
||||
{
|
||||
|
@ -446,7 +437,6 @@ mdclose_fd(int fd)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
_fdvec_free(fd);
|
||||
}
|
||||
|
@ -751,11 +741,8 @@ mdtruncate(Relation reln, int nblocks)
|
|||
int curnblk;
|
||||
int fd;
|
||||
MdfdVec *v;
|
||||
|
||||
#ifndef LET_OS_MANAGE_FILESIZE
|
||||
MemoryContext oldcxt;
|
||||
int priorblocks;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -772,7 +759,6 @@ mdtruncate(Relation reln, int nblocks)
|
|||
v = &Md_fdvec[fd];
|
||||
|
||||
#ifndef LET_OS_MANAGE_FILESIZE
|
||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||
priorblocks = 0;
|
||||
while (v != (MdfdVec *) NULL)
|
||||
{
|
||||
|
@ -825,7 +811,6 @@ mdtruncate(Relation reln, int nblocks)
|
|||
}
|
||||
priorblocks += RELSEG_SIZE;
|
||||
}
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
#else
|
||||
if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
|
||||
return -1;
|
||||
|
@ -833,8 +818,7 @@ mdtruncate(Relation reln, int nblocks)
|
|||
#endif
|
||||
|
||||
return nblocks;
|
||||
|
||||
} /* mdtruncate */
|
||||
}
|
||||
|
||||
/*
|
||||
* mdcommit() -- Commit a transaction.
|
||||
|
@ -907,7 +891,6 @@ _fdvec_alloc()
|
|||
MdfdVec *nvec;
|
||||
int fdvec,
|
||||
i;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
if (Md_Free >= 0) /* get from free list */
|
||||
{
|
||||
|
@ -930,15 +913,11 @@ _fdvec_alloc()
|
|||
|
||||
Nfds *= 2;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||
|
||||
nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
|
||||
nvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
|
||||
MemSet(nvec, 0, Nfds * sizeof(MdfdVec));
|
||||
memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
|
||||
memcpy(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
|
||||
pfree(Md_fdvec);
|
||||
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
Md_fdvec = nvec;
|
||||
|
||||
/* Set new free list */
|
||||
|
@ -976,7 +955,6 @@ _fdvec_free(int fdvec)
|
|||
static MdfdVec *
|
||||
_mdfd_openseg(Relation reln, int segno, int oflags)
|
||||
{
|
||||
MemoryContext oldcxt;
|
||||
MdfdVec *v;
|
||||
int fd;
|
||||
char *path,
|
||||
|
@ -1003,9 +981,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags)
|
|||
return (MdfdVec *) NULL;
|
||||
|
||||
/* allocate an mdfdvec entry for it */
|
||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||
v = (MdfdVec *) palloc(sizeof(MdfdVec));
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
v = (MdfdVec *) MemoryContextAlloc(MdCxt, sizeof(MdfdVec));
|
||||
|
||||
/* fill the entry */
|
||||
v->mdfd_vfd = fd;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.161 2000/06/22 22:31:20 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.162 2000/06/28 03:32:18 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
|
@ -79,7 +79,6 @@ bool Log_connections = false;
|
|||
CommandDest whereToSendOutput = Debug;
|
||||
|
||||
|
||||
extern void BaseInit(void);
|
||||
extern void StartupXLOG(void);
|
||||
extern void ShutdownXLOG(void);
|
||||
|
||||
|
@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS);
|
|||
extern char XLogDir[];
|
||||
extern char ControlFilePath[];
|
||||
|
||||
extern int lockingOff;
|
||||
extern int NBuffers;
|
||||
static bool dontExecute = false;
|
||||
|
||||
int dontExecute = 0;
|
||||
static bool IsEmptyQuery = false;
|
||||
|
||||
/* note: these declarations had better match tcopprot.h */
|
||||
|
@ -101,8 +98,6 @@ bool Warn_restart_ready = false;
|
|||
bool InError = false;
|
||||
bool ExitAfterAbort = false;
|
||||
|
||||
extern int NBuffers;
|
||||
|
||||
static bool EchoQuery = false; /* default don't echo */
|
||||
char pg_pathname[MAXPGPATH];
|
||||
FILE *StatFp = NULL;
|
||||
|
@ -133,7 +128,6 @@ int XfuncMode = 0;
|
|||
static int InteractiveBackend(StringInfo inBuf);
|
||||
static int SocketBackend(StringInfo inBuf);
|
||||
static int ReadCommand(StringInfo inBuf);
|
||||
static void pg_exec_query(char *query_string);
|
||||
static void SigHupHandler(SIGNAL_ARGS);
|
||||
static void FloatExceptionHandler(SIGNAL_ARGS);
|
||||
static void quickdie(SIGNAL_ARGS);
|
||||
|
@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf)
|
|||
static int
|
||||
ReadCommand(StringInfo inBuf)
|
||||
{
|
||||
MemoryContext oldcontext;
|
||||
int result;
|
||||
|
||||
/*
|
||||
* Make sure any expansion of inBuf happens in permanent memory
|
||||
* context, so that we can keep using it for future command cycles.
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
if (IsUnderPostmaster)
|
||||
result = SocketBackend(inBuf);
|
||||
else
|
||||
result = InteractiveBackend(inBuf);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf)
|
|||
* multiple queries and/or the rewriter might expand one query to several.
|
||||
*/
|
||||
List *
|
||||
pg_parse_and_rewrite(char *query_string, /* string to execute */
|
||||
Oid *typev,/* argument types */
|
||||
int nargs, /* number of arguments */
|
||||
bool aclOverride)
|
||||
pg_parse_and_rewrite(char *query_string, /* string to execute */
|
||||
Oid *typev, /* parameter types */
|
||||
int nargs) /* number of parameters */
|
||||
{
|
||||
List *querytree_list;
|
||||
List *querytree_list_item;
|
||||
|
@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
|
|||
|
||||
querytree_list = new_list;
|
||||
|
||||
/* ----------------
|
||||
* (3) If ACL override is requested, mark queries for no ACL check.
|
||||
* ----------------
|
||||
*/
|
||||
if (aclOverride)
|
||||
{
|
||||
foreach(querytree_list_item, querytree_list)
|
||||
{
|
||||
List *l;
|
||||
|
||||
querytree = (Query *) lfirst(querytree_list_item);
|
||||
|
||||
if (querytree->commandType == CMD_UTILITY)
|
||||
continue;
|
||||
|
||||
foreach(l, querytree->rtable)
|
||||
{
|
||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
||||
|
||||
rte->skipAcl = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Debug_print_rewritten)
|
||||
{
|
||||
if (Debug_pretty_print)
|
||||
|
@ -516,63 +478,66 @@ pg_plan_query(Query *querytree)
|
|||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* pg_exec_query()
|
||||
* pg_exec_query_dest()
|
||||
*
|
||||
* Takes a querystring, runs the parser/utilities or
|
||||
* parser/planner/executor over it as necessary
|
||||
* Begin Transaction Should have been called before this
|
||||
* and CommitTransaction After this is called
|
||||
* This is strictly because we do not allow for nested xactions.
|
||||
* parser/planner/executor over it as necessary.
|
||||
*
|
||||
* NON-OBVIOUS-RESTRICTIONS
|
||||
* this function _MUST_ allocate a new "parsetree" each time,
|
||||
* since it may be stored in a named portal and should not
|
||||
* change its value.
|
||||
* Assumptions:
|
||||
*
|
||||
* Caller is responsible for calling StartTransactionCommand() beforehand
|
||||
* and CommitTransactionCommand() afterwards (if successful).
|
||||
*
|
||||
* The CurrentMemoryContext at entry references a context that is
|
||||
* appropriate for execution of individual queries (typically this will be
|
||||
* TransactionCommandContext). Note that this routine resets that context
|
||||
* after each individual query, so don't store anything there that
|
||||
* must outlive the call!
|
||||
*
|
||||
* parse_context references a context suitable for holding the
|
||||
* parse/rewrite trees (typically this will be QueryContext).
|
||||
* This context must be longer-lived than the CurrentMemoryContext!
|
||||
* In fact, if the query string might contain BEGIN/COMMIT commands,
|
||||
* parse_context had better outlive TopTransactionContext!
|
||||
*
|
||||
* We could have hard-wired knowledge about QueryContext and
|
||||
* TransactionCommandContext into this routine, but it seems better
|
||||
* not to, in case callers from outside this module need to use some
|
||||
* other contexts.
|
||||
*
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
pg_exec_query(char *query_string)
|
||||
{
|
||||
pg_exec_query_dest(query_string, whereToSendOutput, FALSE);
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
void
|
||||
pg_exec_query_acl_override(char *query_string)
|
||||
{
|
||||
pg_exec_query_dest(query_string, whereToSendOutput, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
pg_exec_query_dest(char *query_string, /* string to execute */
|
||||
CommandDest dest, /* where results should go */
|
||||
bool aclOverride) /* to give utility commands power
|
||||
* of superusers */
|
||||
MemoryContext parse_context) /* context for parsetrees */
|
||||
{
|
||||
List *querytree_list;
|
||||
|
||||
/* parse and rewrite the queries */
|
||||
querytree_list = pg_parse_and_rewrite(query_string, NULL, 0,
|
||||
aclOverride);
|
||||
MemoryContext oldcontext;
|
||||
List *querytree_list,
|
||||
*querytree_item;
|
||||
|
||||
/*
|
||||
* NOTE: we do not use "foreach" here because we want to be sure the
|
||||
* list pointer has been advanced before the query is executed. We
|
||||
* need to do that because VACUUM has a nasty little habit of doing
|
||||
* CommitTransactionCommand at startup, and that will release the
|
||||
* memory holding our parse list :-(. This needs a better solution
|
||||
* --- currently, the code will crash if someone submits "vacuum;
|
||||
* something-else" in a single query string. But memory allocation
|
||||
* needs redesigned anyway, so this will have to do for now.
|
||||
* Switch to appropriate context for constructing parsetrees.
|
||||
*/
|
||||
while (querytree_list)
|
||||
{
|
||||
Query *querytree = (Query *) lfirst(querytree_list);
|
||||
oldcontext = MemoryContextSwitchTo(parse_context);
|
||||
|
||||
querytree_list = lnext(querytree_list);
|
||||
/*
|
||||
* Parse and rewrite the query or queries.
|
||||
*/
|
||||
querytree_list = pg_parse_and_rewrite(query_string, NULL, 0);
|
||||
|
||||
/*
|
||||
* Switch back to execution context for planning and execution.
|
||||
*/
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
/*
|
||||
* Run through the query or queries and execute each one.
|
||||
*/
|
||||
foreach(querytree_item, querytree_list)
|
||||
{
|
||||
Query *querytree = (Query *) lfirst(querytree_item);
|
||||
|
||||
/* if we got a cancel signal in parsing or prior command, quit */
|
||||
if (QueryCancel)
|
||||
|
@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string, /* string to execute */
|
|||
if (Show_executor_stats)
|
||||
ResetUsage();
|
||||
|
||||
if (DebugLvl > 1)
|
||||
elog(DEBUG, "ProcessQuery");
|
||||
ProcessQuery(querytree, plan, dest);
|
||||
if (dontExecute)
|
||||
{
|
||||
/* don't execute it, just show the query plan */
|
||||
print_plan(plan, querytree);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DebugLvl > 1)
|
||||
elog(DEBUG, "ProcessQuery");
|
||||
ProcessQuery(querytree, plan, dest);
|
||||
}
|
||||
|
||||
if (Show_executor_stats)
|
||||
{
|
||||
|
@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string, /* string to execute */
|
|||
* between queries so that the effects of early queries are
|
||||
* visible to subsequent ones.
|
||||
*/
|
||||
|
||||
CommandCounterIncrement();
|
||||
/*
|
||||
* Also, clear the execution context to recover temporary
|
||||
* memory used by the query. NOTE: if query string contains
|
||||
* BEGIN/COMMIT transaction commands, execution context may
|
||||
* now be different from what we were originally passed;
|
||||
* so be careful to clear current context not "oldcontext".
|
||||
*/
|
||||
MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -821,6 +801,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
extern char *optarg;
|
||||
extern int DebugLvl;
|
||||
|
||||
/*
|
||||
* Fire up essential subsystems: error and memory management
|
||||
*
|
||||
* If we are running under the postmaster, this is done already.
|
||||
*/
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
EnableExceptionHandling(true);
|
||||
MemoryContextInit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set default values for command-line options.
|
||||
*/
|
||||
|
@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
break;
|
||||
|
||||
case 'i':
|
||||
dontExecute = 1;
|
||||
dontExecute = true;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
|
@ -1182,11 +1173,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
*
|
||||
* Note that postmaster already blocked ALL signals to make us happy.
|
||||
*/
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
PG_INITMASK();
|
||||
PG_SETMASK(&BlockSig);
|
||||
}
|
||||
pqinitmask();
|
||||
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigdelset(&BlockSig, SIGUSR1);
|
||||
|
@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
BlockSig &= ~(sigmask(SIGUSR1));
|
||||
#endif
|
||||
|
||||
PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
|
||||
|
||||
pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
|
||||
pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
|
||||
pqsignal(SIGQUIT, handle_warn); /* handle error */
|
||||
|
@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
pqsignal(SIGTTOU, SIG_DFL);
|
||||
pqsignal(SIGCONT, SIG_DFL);
|
||||
|
||||
PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
|
||||
|
||||
/*
|
||||
* Get user name (needed now in case it is the default database name)
|
||||
* and check command line validity
|
||||
|
@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
|
||||
on_shmem_exit(remove_all_temp_relations, NULL);
|
||||
|
||||
{
|
||||
MemoryContext oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
parser_input = makeStringInfo(); /* initialize input buffer */
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send this backend's cancellation info to the frontend.
|
||||
*/
|
||||
|
@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
if (!IsUnderPostmaster)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface ");
|
||||
puts("$Revision: 1.161 $ $Date: 2000/06/22 22:31:20 $\n");
|
||||
puts("$Revision: 1.162 $ $Date: 2000/06/28 03:32:18 $\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1397,6 +1377,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
|
||||
SetProcessingMode(NormalProcessing);
|
||||
|
||||
/*
|
||||
* Create the memory context we will use in the main loop.
|
||||
*
|
||||
* QueryContext is reset once per iteration of the main loop,
|
||||
* ie, upon completion of processing of each supplied query string.
|
||||
* It can therefore be used for any data that should live just as
|
||||
* long as the query string --- parse trees, for example.
|
||||
*/
|
||||
QueryContext = AllocSetContextCreate(TopMemoryContext,
|
||||
"QueryContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
/*
|
||||
* POSTGRES main processing loop begins here
|
||||
*
|
||||
|
@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
|
||||
if (sigsetjmp(Warn_restart, 1) != 0)
|
||||
{
|
||||
/* Make sure we are in a valid memory context */
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
/*
|
||||
* Make sure we are in a valid memory context during recovery.
|
||||
*
|
||||
* We use ErrorContext in hopes that it will have some free space
|
||||
* even if we're otherwise up against it...
|
||||
*/
|
||||
MemoryContextSwitchTo(ErrorContext);
|
||||
|
||||
if (DebugLvl >= 1)
|
||||
elog(DEBUG, "AbortCurrentTransaction");
|
||||
AbortCurrentTransaction();
|
||||
InError = false;
|
||||
|
||||
if (ExitAfterAbort)
|
||||
{
|
||||
ProcReleaseLocks(); /* Just to be sure... */
|
||||
proc_exit(0);
|
||||
}
|
||||
/*
|
||||
* If we recovered successfully, return to normal top-level context
|
||||
* and clear ErrorContext for next time.
|
||||
*/
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
MemoryContextResetAndDeleteChildren(ErrorContext);
|
||||
InError = false;
|
||||
}
|
||||
|
||||
Warn_restart_ready = true; /* we can now handle elog(ERROR) */
|
||||
|
@ -1430,7 +1436,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
|
||||
for (;;)
|
||||
{
|
||||
set_ps_display("idle");
|
||||
/*
|
||||
* Release storage left over from prior query cycle, and
|
||||
* create a new query input buffer in the cleared QueryContext.
|
||||
*/
|
||||
MemoryContextSwitchTo(QueryContext);
|
||||
MemoryContextResetAndDeleteChildren(QueryContext);
|
||||
|
||||
parser_input = makeStringInfo();
|
||||
|
||||
/* XXX this could be moved after ReadCommand below to get more
|
||||
* sensical behaviour */
|
||||
|
@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
* (3) read a command (loop blocks here)
|
||||
* ----------------
|
||||
*/
|
||||
set_ps_display("idle");
|
||||
|
||||
firstchar = ReadCommand(parser_input);
|
||||
|
||||
QueryCancel = false; /* forget any earlier CANCEL signal */
|
||||
|
@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
elog(DEBUG, "StartTransactionCommand");
|
||||
StartTransactionCommand();
|
||||
|
||||
pg_exec_query(parser_input->data);
|
||||
pg_exec_query_dest(parser_input->data,
|
||||
whereToSendOutput,
|
||||
QueryContext);
|
||||
|
||||
/*
|
||||
* Invoke IMMEDIATE constraint triggers
|
||||
|
@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
* (6) commit the current transaction
|
||||
*
|
||||
* Note: if we had an empty input buffer, then we didn't
|
||||
* call pg_exec_query, so we don't bother to commit this transaction.
|
||||
* call pg_exec_query_dest, so we don't bother to commit
|
||||
* this transaction.
|
||||
* ----------------
|
||||
*/
|
||||
if (!IsEmptyQuery)
|
||||
|
@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||
#ifdef SHOW_MEMORY_STATS
|
||||
/* print global-context stats at each commit for leak tracking */
|
||||
if (ShowStats)
|
||||
GlobalMemoryStats();
|
||||
MemoryContextStats(TopMemoryContext);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.34 2000/06/12 03:40:40 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.35 2000/06/28 03:32:22 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -22,8 +22,6 @@
|
|||
#include "utils/ps_status.h"
|
||||
|
||||
static char *CreateOperationTag(int operationType);
|
||||
static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
|
||||
Node *limcount);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
@ -115,7 +113,7 @@ CreateOperationTag(int operationType)
|
|||
default:
|
||||
elog(DEBUG, "CreateOperationTag: unknown operation type %d",
|
||||
operationType);
|
||||
tag = NULL;
|
||||
tag = "???";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -123,31 +121,18 @@ CreateOperationTag(int operationType)
|
|||
}
|
||||
|
||||
/* ----------------
|
||||
* ProcessPortal
|
||||
* PreparePortal
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
void
|
||||
ProcessPortal(char *portalName,
|
||||
Query *parseTree,
|
||||
Plan *plan,
|
||||
EState *state,
|
||||
TupleDesc attinfo,
|
||||
CommandDest dest)
|
||||
Portal
|
||||
PreparePortal(char *portalName)
|
||||
{
|
||||
Portal portal;
|
||||
MemoryContext portalContext;
|
||||
|
||||
/* ----------------
|
||||
* Check for reserved or already-in-use portal name.
|
||||
* Check for already-in-use portal name.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (PortalNameIsSpecial(portalName))
|
||||
elog(ERROR,
|
||||
"The portal name \"%s\" is reserved for internal use",
|
||||
portalName);
|
||||
|
||||
portal = GetPortalByName(portalName);
|
||||
if (PortalIsValid(portal))
|
||||
{
|
||||
|
@ -158,70 +143,39 @@ ProcessPortal(char *portalName,
|
|||
}
|
||||
|
||||
/* ----------------
|
||||
* Convert the current blank portal into the user-specified
|
||||
* portal and initialize the state and query descriptor.
|
||||
*
|
||||
* Since the parsetree has been created in the current blank portal,
|
||||
* we don't have to do any work to copy it into the user-named portal.
|
||||
* Create the new portal and make its memory context active.
|
||||
* ----------------
|
||||
*/
|
||||
portal = CreatePortal(portalName);
|
||||
|
||||
portal = BlankPortalAssignName(portalName);
|
||||
MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||
|
||||
PortalSetQuery(portal,
|
||||
CreateQueryDesc(parseTree, plan, dest),
|
||||
attinfo,
|
||||
state,
|
||||
PortalCleanup);
|
||||
|
||||
/* ----------------
|
||||
* Now create a new blank portal and switch to it.
|
||||
* Otherwise, the new named portal will be cleaned at statement end.
|
||||
*
|
||||
* Note: portals will only be supported within a BEGIN...END
|
||||
* block in the near future. Later, someone will fix it to
|
||||
* do what is possible across transaction boundries. -hirohama
|
||||
* ----------------
|
||||
*/
|
||||
portalContext = (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL));
|
||||
|
||||
MemoryContextSwitchTo(portalContext);
|
||||
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
return portal;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ProcessQueryDesc
|
||||
* ProcessQuery
|
||||
*
|
||||
* Read the comments for ProcessQuery() below...
|
||||
* Execute a plan, the non-parallel version
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
||||
void
|
||||
ProcessQuery(Query *parsetree,
|
||||
Plan *plan,
|
||||
CommandDest dest)
|
||||
{
|
||||
Query *parseTree;
|
||||
Plan *plan;
|
||||
int operation;
|
||||
char *tag = NULL;
|
||||
int operation = parsetree->commandType;
|
||||
char *tag;
|
||||
bool isRetrieveIntoPortal;
|
||||
bool isRetrieveIntoRelation;
|
||||
Portal portal = NULL;
|
||||
char *intoName = NULL;
|
||||
QueryDesc *queryDesc;
|
||||
EState *state;
|
||||
TupleDesc attinfo;
|
||||
|
||||
bool isRetrieveIntoPortal;
|
||||
bool isRetrieveIntoRelation;
|
||||
char *intoName = NULL;
|
||||
CommandDest dest;
|
||||
|
||||
/* ----------------
|
||||
* get info from the query desc
|
||||
* ----------------
|
||||
*/
|
||||
parseTree = queryDesc->parsetree;
|
||||
plan = queryDesc->plantree;
|
||||
|
||||
operation = queryDesc->operation;
|
||||
set_ps_display(tag = CreateOperationTag(operation));
|
||||
dest = queryDesc->dest;
|
||||
|
||||
/* ----------------
|
||||
* initialize portal/into relation status
|
||||
|
@ -232,11 +186,11 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||
|
||||
if (operation == CMD_SELECT)
|
||||
{
|
||||
if (parseTree->isPortal)
|
||||
if (parsetree->isPortal)
|
||||
{
|
||||
isRetrieveIntoPortal = true;
|
||||
intoName = parseTree->into;
|
||||
if (parseTree->isBinary)
|
||||
intoName = parsetree->into;
|
||||
if (parsetree->isBinary)
|
||||
{
|
||||
|
||||
/*
|
||||
|
@ -244,19 +198,38 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||
* (externalized form) to RemoteInternal (internalized
|
||||
* form)
|
||||
*/
|
||||
dest = queryDesc->dest = RemoteInternal;
|
||||
dest = RemoteInternal;
|
||||
}
|
||||
}
|
||||
else if (parseTree->into != NULL)
|
||||
else if (parsetree->into != NULL)
|
||||
{
|
||||
/* select into table */
|
||||
isRetrieveIntoRelation = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* when performing a retrieve into, we override the normal
|
||||
* If retrieving into a portal, set up the portal and copy
|
||||
* the parsetree and plan into its memory context.
|
||||
* ----------------
|
||||
*/
|
||||
if (isRetrieveIntoPortal)
|
||||
{
|
||||
portal = PreparePortal(intoName);
|
||||
/* CurrentMemoryContext is now pointing to portal's context */
|
||||
parsetree = copyObject(parsetree);
|
||||
plan = copyObject(plan);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* Now we can create the QueryDesc object (this is also in
|
||||
* the portal context, if portal retrieve).
|
||||
* ----------------
|
||||
*/
|
||||
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
||||
|
||||
/* ----------------
|
||||
* When performing a retrieve into, we override the normal
|
||||
* communication destination during the processing of the
|
||||
* the query. This only affects the tuple-output function
|
||||
* - the correct destination will still see BeginCommand()
|
||||
|
@ -293,26 +266,19 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||
dest);
|
||||
|
||||
/* ----------------
|
||||
* Named portals do not do a "fetch all" initially, so now
|
||||
* we return since ExecMain has been called with EXEC_START
|
||||
* to initialize the query plan.
|
||||
*
|
||||
* Note: ProcessPortal transforms the current "blank" portal
|
||||
* into a named portal and creates a new blank portal so
|
||||
* everything we allocated in the current "blank" memory
|
||||
* context will be preserved across queries. -cim 2/22/91
|
||||
* If retrieve into portal, stop now; we do not run the plan
|
||||
* until a FETCH command is received.
|
||||
* ----------------
|
||||
*/
|
||||
if (isRetrieveIntoPortal)
|
||||
{
|
||||
PortalExecutorHeapMemory = NULL;
|
||||
PortalSetQuery(portal,
|
||||
queryDesc,
|
||||
attinfo,
|
||||
state,
|
||||
PortalCleanup);
|
||||
|
||||
ProcessPortal(intoName,
|
||||
parseTree,
|
||||
plan,
|
||||
state,
|
||||
attinfo,
|
||||
dest);
|
||||
MemoryContextSwitchTo(TransactionCommandContext);
|
||||
|
||||
EndCommand(tag, dest);
|
||||
return;
|
||||
|
@ -323,14 +289,14 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||
* actually run the plan..
|
||||
* ----------------
|
||||
*/
|
||||
ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
|
||||
ExecutorRun(queryDesc, state, EXEC_RUN,
|
||||
parsetree->limitOffset, parsetree->limitCount);
|
||||
|
||||
/* save infos for EndCommand */
|
||||
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
||||
|
||||
/* ----------------
|
||||
* now, we close down all the scans and free allocated resources...
|
||||
* with ExecutorEnd()
|
||||
* Now, we close down all the scans and free allocated resources.
|
||||
* ----------------
|
||||
*/
|
||||
ExecutorEnd(queryDesc, state);
|
||||
|
@ -341,31 +307,3 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||
*/
|
||||
EndCommand(tag, dest);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ProcessQuery
|
||||
*
|
||||
* Execute a plan, the non-parallel version
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ProcessQuery(Query *parsetree,
|
||||
Plan *plan,
|
||||
CommandDest dest)
|
||||
{
|
||||
QueryDesc *queryDesc;
|
||||
extern int dontExecute; /* from postgres.c */
|
||||
extern void print_plan(Plan *p, Query *parsetree); /* from print.c */
|
||||
|
||||
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
||||
|
||||
if (dontExecute)
|
||||
{
|
||||
/* don't execute it, just show the query plan */
|
||||
print_plan(plan, parsetree);
|
||||
}
|
||||
else
|
||||
ProcessQueryDesc(queryDesc, parsetree->limitOffset,
|
||||
parsetree->limitCount);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.67 2000/06/19 03:54:31 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.68 2000/06/28 03:32:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -60,10 +60,6 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
|
|||
|
||||
static CatCache *Caches = NULL; /* head of list of caches */
|
||||
|
||||
GlobalMemory CacheCxt; /* context in which caches are allocated */
|
||||
|
||||
/* CacheCxt is global because relcache uses it too. */
|
||||
|
||||
|
||||
/* ----------------
|
||||
* EQPROC is used in CatalogCacheInitializeCache to find the equality
|
||||
|
@ -135,6 +131,28 @@ cc_hashname(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Standard routine for creating cache context if it doesn't exist yet
|
||||
*
|
||||
* There are a lot of places (probably far more than necessary) that check
|
||||
* whether CacheMemoryContext exists yet and want to create it if not.
|
||||
* We centralize knowledge of exactly how to create it here.
|
||||
*/
|
||||
void
|
||||
CreateCacheMemoryContext(void)
|
||||
{
|
||||
/* Purely for paranoia, check that context doesn't exist;
|
||||
* caller probably did so already.
|
||||
*/
|
||||
if (!CacheMemoryContext)
|
||||
CacheMemoryContext = AllocSetContextCreate(TopMemoryContext,
|
||||
"CacheMemoryContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------
|
||||
* CatalogCacheInitializeCache
|
||||
* --------------------------------
|
||||
|
@ -183,9 +201,10 @@ CatalogCacheInitializeCache(CatCache * cache,
|
|||
* do not vanish at the end of a transaction
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* If no relation was passed we must open it to get access to
|
||||
|
@ -415,7 +434,7 @@ CatalogCacheComputeTupleHashIndex(CatCache * cacheInOutP,
|
|||
/* --------------------------------
|
||||
* CatCacheRemoveCTup
|
||||
*
|
||||
* NB: assumes caller has switched to CacheCxt
|
||||
* NB: assumes caller has switched to CacheMemoryContext
|
||||
* --------------------------------
|
||||
*/
|
||||
static void
|
||||
|
@ -477,9 +496,10 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */
|
|||
* switch to the cache context for our memory allocations
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* inspect every cache that could contain the tuple
|
||||
|
@ -552,10 +572,10 @@ ResetSystemCache()
|
|||
* do not vanish at the end of a transaction
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* here we purge the contents of all the caches
|
||||
|
@ -681,10 +701,10 @@ InitSysCache(char *relname,
|
|||
* do not vanish at the end of a transaction
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* allocate a new cache structure
|
||||
|
@ -839,14 +859,14 @@ SearchSelfReferences(CatCache * cache)
|
|||
HeapScanDesc sd;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
rel = heap_open(cache->relationId, AccessShareLock);
|
||||
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
|
||||
ntp = heap_getnext(sd, 0);
|
||||
if (!HeapTupleIsValid(ntp))
|
||||
elog(ERROR, "SearchSelfReferences: tuple not found");
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
indexSelfTuple = heap_copytuple(ntp);
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
heap_endscan(sd);
|
||||
|
@ -868,14 +888,14 @@ SearchSelfReferences(CatCache * cache)
|
|||
HeapScanDesc sd;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
rel = heap_open(cache->relationId, AccessShareLock);
|
||||
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
|
||||
ntp = heap_getnext(sd, 0);
|
||||
if (!HeapTupleIsValid(ntp))
|
||||
elog(ERROR, "SearchSelfReferences: tuple not found");
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
heap_endscan(sd);
|
||||
|
@ -908,7 +928,6 @@ SearchSysCache(CatCache * cache,
|
|||
CatCTup *nct2;
|
||||
Dlelem *elt;
|
||||
HeapTuple ntp = NULL;
|
||||
|
||||
Relation relation;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
|
@ -1020,10 +1039,10 @@ SearchSysCache(CatCache * cache,
|
|||
* ----------------
|
||||
*/
|
||||
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* Scan the relation to find the tuple. If there's an index, and
|
||||
|
@ -1060,12 +1079,13 @@ SearchSysCache(CatCache * cache,
|
|||
*/
|
||||
if (HeapTupleIsValid(indextp))
|
||||
{
|
||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
MemoryContextSwitchTo(CacheMemoryContext);
|
||||
ntp = heap_copytuple(indextp);
|
||||
/* this switch is probably not needed anymore: */
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
heap_freetuple(indextp);
|
||||
}
|
||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
MemoryContextSwitchTo(CacheMemoryContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1084,7 +1104,7 @@ SearchSysCache(CatCache * cache,
|
|||
|
||||
ntp = heap_getnext(sd, 0);
|
||||
|
||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
if (HeapTupleIsValid(ntp))
|
||||
{
|
||||
|
@ -1097,7 +1117,7 @@ SearchSysCache(CatCache * cache,
|
|||
|
||||
heap_endscan(sd);
|
||||
|
||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
MemoryContextSwitchTo(CacheMemoryContext);
|
||||
}
|
||||
|
||||
cache->busy = false;
|
||||
|
@ -1205,9 +1225,10 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
|
|||
* switch to the cache memory context
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* for each cache
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.103 2000/06/19 23:40:48 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.104 2000/06/28 03:32:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -917,10 +917,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||
/* ----------------
|
||||
* allocate storage for the relation descriptor,
|
||||
* initialize relation->rd_rel and get the access method id.
|
||||
* The storage is allocated in memory context CacheCxt.
|
||||
* The storage is allocated in memory context CacheMemoryContext.
|
||||
* ----------------
|
||||
*/
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
relation = AllocateRelationDesc(oldrelation, natts, relp);
|
||||
relam = relation->rd_rel->relam;
|
||||
|
||||
|
@ -1383,7 +1383,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||
if (relation->rd_isnailed)
|
||||
return;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/*
|
||||
* Remove relation from hash tables
|
||||
|
@ -1574,7 +1574,7 @@ RelationForgetRelation(Oid rid)
|
|||
List *curr;
|
||||
List *prev = NIL;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
foreach(curr, newlyCreatedRelns)
|
||||
{
|
||||
|
@ -1731,10 +1731,7 @@ RelationRegisterRelation(Relation relation)
|
|||
{
|
||||
MemoryContext oldcxt;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
|
||||
if (oldcxt != (MemoryContext) CacheCxt)
|
||||
elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
RelationInitLockInfo(relation);
|
||||
|
||||
|
@ -1769,7 +1766,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
|
|||
if (newlyCreatedRelns == NULL)
|
||||
return;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
while (newlyCreatedRelns)
|
||||
{
|
||||
|
@ -1822,10 +1819,10 @@ RelationInitialize(void)
|
|||
* switch to cache memory context
|
||||
* ----------------
|
||||
*/
|
||||
if (!CacheCxt)
|
||||
CacheCxt = CreateGlobalMemory("Cache");
|
||||
if (!CacheMemoryContext)
|
||||
CreateCacheMemoryContext();
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* create global caches
|
||||
|
@ -2186,7 +2183,7 @@ RelationGetIndexList(Relation relation)
|
|||
heap_close(indrel, AccessShareLock);
|
||||
|
||||
/* Now save a copy of the completed list in the relcache entry. */
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
relation->rd_indexlist = listCopy(result);
|
||||
relation->rd_indexfound = true;
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.24 2000/06/20 06:41:12 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.25 2000/06/28 03:32:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -67,7 +67,7 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
|
|||
MemoryContext oldcxt;
|
||||
TempTable *temp_rel;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
temp_rel = (TempTable *) palloc(sizeof(TempTable));
|
||||
temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
|
||||
|
@ -135,7 +135,7 @@ remove_temp_relation(Oid relid)
|
|||
List *l,
|
||||
*prev;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
prev = NIL;
|
||||
l = temp_rels;
|
||||
|
@ -185,7 +185,7 @@ invalidate_temp_relations(void)
|
|||
List *l,
|
||||
*prev;
|
||||
|
||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
||||
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
prev = NIL;
|
||||
l = temp_rels;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.60 2000/06/04 15:06:29 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.61 2000/06/28 03:32:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -27,7 +27,7 @@
|
|||
#include <sys/time.h>
|
||||
#include <ctype.h>
|
||||
#ifdef ENABLE_SYSLOG
|
||||
# include <syslog.h>
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#include "libpq/libpq.h"
|
||||
|
@ -89,10 +89,9 @@ static int ElogDebugIndentLevel = 0;
|
|||
*--------------------
|
||||
*/
|
||||
void
|
||||
elog(int lev, const char *fmt,...)
|
||||
elog(int lev, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* The expanded format and final output message are dynamically
|
||||
* allocated if necessary, but not if they fit in the "reasonable
|
||||
|
@ -101,12 +100,21 @@ elog(int lev, const char *fmt,...)
|
|||
* working (since memory-clobber errors often take out malloc first).
|
||||
* Don't make these buffers unreasonably large though, on pain of
|
||||
* having to chase a bug with no error message.
|
||||
*
|
||||
* Note that we use malloc() not palloc() because we want to retain
|
||||
* control if we run out of memory. palloc() would recursively call
|
||||
* elog(ERROR), which would be all right except if we are working on a
|
||||
* FATAL or REALLYFATAL error. We'd lose track of the fatal condition
|
||||
* and report a mere ERROR to outer loop, which would be a Bad Thing.
|
||||
* So, we substitute an appropriate message in-place, without downgrading
|
||||
* the level if it's above ERROR.
|
||||
*/
|
||||
char fmt_fixedbuf[128];
|
||||
char msg_fixedbuf[256];
|
||||
char *fmt_buf = fmt_fixedbuf;
|
||||
char *msg_buf = msg_fixedbuf;
|
||||
|
||||
/* this buffer is only used for strange values of lev: */
|
||||
char prefix_buf[32];
|
||||
/* this buffer is only used if errno has a bogus value: */
|
||||
char errorstr_buf[32];
|
||||
const char *errorstr;
|
||||
|
@ -115,7 +123,6 @@ elog(int lev, const char *fmt,...)
|
|||
char *bp;
|
||||
int indent = 0;
|
||||
int space_needed;
|
||||
|
||||
int len;
|
||||
/* size of the prefix needed for timestamp and pid, if enabled */
|
||||
size_t timestamp_size;
|
||||
|
@ -123,6 +130,15 @@ elog(int lev, const char *fmt,...)
|
|||
if (lev <= DEBUG && Debugfile < 0)
|
||||
return; /* ignore debug msgs if noplace to send */
|
||||
|
||||
/* save errno string for %m */
|
||||
if (errno < sys_nerr && errno >= 0)
|
||||
errorstr = strerror(errno);
|
||||
else
|
||||
{
|
||||
sprintf(errorstr_buf, "error %d", errno);
|
||||
errorstr = errorstr_buf;
|
||||
}
|
||||
|
||||
if (lev == ERROR || lev == FATAL)
|
||||
{
|
||||
/* this is probably redundant... */
|
||||
|
@ -156,21 +172,11 @@ elog(int lev, const char *fmt,...)
|
|||
prefix = "ERROR: ";
|
||||
break;
|
||||
default:
|
||||
/* temporarily use msg buf for prefix */
|
||||
sprintf(msg_fixedbuf, "FATAL %d: ", lev);
|
||||
prefix = msg_fixedbuf;
|
||||
sprintf(prefix_buf, "FATAL %d: ", lev);
|
||||
prefix = prefix_buf;
|
||||
break;
|
||||
}
|
||||
|
||||
/* get errno string for %m */
|
||||
if (errno < sys_nerr && errno >= 0)
|
||||
errorstr = strerror(errno);
|
||||
else
|
||||
{
|
||||
sprintf(errorstr_buf, "error %d", errno);
|
||||
errorstr = errorstr_buf;
|
||||
}
|
||||
|
||||
timestamp_size = 0;
|
||||
if (Log_timestamp)
|
||||
timestamp_size += TIMESTAMP_SIZE;
|
||||
|
@ -190,9 +196,13 @@ elog(int lev, const char *fmt,...)
|
|||
fmt_buf = (char *) malloc(space_needed);
|
||||
if (fmt_buf == NULL)
|
||||
{
|
||||
/* We're up against it, convert to fatal out-of-memory error */
|
||||
/* We're up against it, convert to out-of-memory error */
|
||||
fmt_buf = fmt_fixedbuf;
|
||||
lev = REALLYFATAL;
|
||||
if (lev < FATAL)
|
||||
{
|
||||
lev = ERROR;
|
||||
prefix = "ERROR: ";
|
||||
}
|
||||
fmt = "elog: out of memory"; /* this must fit in
|
||||
* fmt_fixedbuf! */
|
||||
}
|
||||
|
@ -281,15 +291,20 @@ elog(int lev, const char *fmt,...)
|
|||
msg_buf = (char *) malloc(space_needed);
|
||||
if (msg_buf == NULL)
|
||||
{
|
||||
/* We're up against it, convert to fatal out-of-memory error */
|
||||
/* We're up against it, convert to out-of-memory error */
|
||||
msg_buf = msg_fixedbuf;
|
||||
lev = REALLYFATAL;
|
||||
if (lev < FATAL)
|
||||
{
|
||||
lev = ERROR;
|
||||
prefix = "ERROR: ";
|
||||
}
|
||||
msg_buf[0] = '\0';
|
||||
if (Log_timestamp)
|
||||
strcat(msg_buf, print_timestamp());
|
||||
if (Log_pid)
|
||||
strcat(msg_buf, print_pid());
|
||||
strcat(msg_buf, "FATAL: elog: out of memory");
|
||||
strcat(msg_buf, prefix);
|
||||
strcat(msg_buf, "elog: out of memory");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.42 2000/06/15 04:10:29 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.43 2000/06/28 03:32:31 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -134,7 +134,7 @@ load_external_function(char *filename, char *funcname)
|
|||
file_scanner = (DynamicFileList *)
|
||||
malloc(sizeof(DynamicFileList) + strlen(filename));
|
||||
if (file_scanner == NULL)
|
||||
elog(FATAL, "Out of memory in load_external_function");
|
||||
elog(ERROR, "Out of memory in load_external_function");
|
||||
|
||||
MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
|
||||
strcpy(file_scanner->filename, filename);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.31 2000/04/12 17:16:00 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.32 2000/06/28 03:32:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -56,8 +56,7 @@
|
|||
/*
|
||||
* Private function prototypes
|
||||
*/
|
||||
static long *DynaHashAlloc(unsigned int size);
|
||||
static void DynaHashFree(Pointer ptr);
|
||||
static void *DynaHashAlloc(Size size);
|
||||
static uint32 call_hash(HTAB *hashp, char *k);
|
||||
static SEG_OFFSET seg_alloc(HTAB *hashp);
|
||||
static int bucket_alloc(HTAB *hashp);
|
||||
|
@ -66,9 +65,7 @@ static int expand_table(HTAB *hashp);
|
|||
static int hdefault(HTAB *hashp);
|
||||
static int init_htab(HTAB *hashp, int nelem);
|
||||
|
||||
typedef long *((*dhalloc_ptr) ());
|
||||
|
||||
#ifndef FRONTEND
|
||||
/* ----------------
|
||||
* memory allocation routines
|
||||
*
|
||||
|
@ -84,34 +81,24 @@ typedef long *((*dhalloc_ptr) ());
|
|||
* do the latter -cim 1/19/91
|
||||
* ----------------
|
||||
*/
|
||||
GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
|
||||
static MemoryContext DynaHashCxt = NULL;
|
||||
|
||||
static long *
|
||||
DynaHashAlloc(unsigned int size)
|
||||
static void *
|
||||
DynaHashAlloc(Size size)
|
||||
{
|
||||
if (!DynaHashCxt)
|
||||
DynaHashCxt = CreateGlobalMemory("DynaHash");
|
||||
DynaHashCxt = AllocSetContextCreate(TopMemoryContext,
|
||||
"DynaHash",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
return (long *)
|
||||
MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
|
||||
}
|
||||
|
||||
static void
|
||||
DynaHashFree(Pointer ptr)
|
||||
{
|
||||
MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
|
||||
return MemoryContextAlloc(DynaHashCxt, size);
|
||||
}
|
||||
|
||||
#define MEM_ALLOC DynaHashAlloc
|
||||
#define MEM_FREE DynaHashFree
|
||||
|
||||
#else /* FRONTEND */
|
||||
|
||||
#define MEM_ALLOC palloc
|
||||
#define MEM_FREE pfree
|
||||
|
||||
#endif /* FRONTEND */
|
||||
|
||||
|
||||
/*
|
||||
* pointer access macros. Shared memory implementation cannot
|
||||
|
@ -147,7 +134,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
|
|||
HTAB *hashp;
|
||||
|
||||
|
||||
hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
|
||||
hashp = (HTAB *) MEM_ALLOC(sizeof(HTAB));
|
||||
MemSet(hashp, 0, sizeof(HTAB));
|
||||
|
||||
if (flags & HASH_FUNCTION)
|
||||
|
@ -181,7 +168,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
|
|||
/* setup hash table defaults */
|
||||
|
||||
hashp->hctl = NULL;
|
||||
hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
|
||||
hashp->alloc = MEM_ALLOC;
|
||||
hashp->dir = NULL;
|
||||
hashp->segbase = NULL;
|
||||
|
||||
|
@ -189,7 +176,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
|
|||
|
||||
if (!hashp->hctl)
|
||||
{
|
||||
hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
|
||||
hashp->hctl = (HHDR *) hashp->alloc(sizeof(HHDR));
|
||||
if (!hashp->hctl)
|
||||
return 0;
|
||||
}
|
||||
|
@ -318,7 +305,8 @@ init_htab(HTAB *hashp, int nelem)
|
|||
/* Allocate a directory */
|
||||
if (!(hashp->dir))
|
||||
{
|
||||
hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
|
||||
hashp->dir = (SEG_OFFSET *)
|
||||
hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
|
||||
if (!hashp->dir)
|
||||
return -1;
|
||||
}
|
||||
|
@ -445,7 +433,7 @@ hash_destroy(HTAB *hashp)
|
|||
/* cannot destroy a shared memory hash table */
|
||||
Assert(!hashp->segbase);
|
||||
/* allocation method must be one we know how to free, too */
|
||||
Assert(hashp->alloc == (dhalloc_ptr) MEM_ALLOC);
|
||||
Assert(hashp->alloc == MEM_ALLOC);
|
||||
|
||||
hash_stats("destroy", hashp);
|
||||
|
||||
|
@ -885,7 +873,7 @@ dir_realloc(HTAB *hashp)
|
|||
new_dirsize = new_dsize * sizeof(SEG_OFFSET);
|
||||
|
||||
old_p = (char *) hashp->dir;
|
||||
p = (char *) hashp->alloc((unsigned long) new_dirsize);
|
||||
p = (char *) hashp->alloc((Size) new_dirsize);
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
|
@ -906,8 +894,7 @@ seg_alloc(HTAB *hashp)
|
|||
SEGMENT segp;
|
||||
SEG_OFFSET segOffset;
|
||||
|
||||
segp = (SEGMENT) hashp->alloc((unsigned long)
|
||||
sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
|
||||
segp = (SEGMENT) hashp->alloc(sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
|
||||
|
||||
if (!segp)
|
||||
return 0;
|
||||
|
@ -937,8 +924,7 @@ bucket_alloc(HTAB *hashp)
|
|||
/* make sure its aligned correctly */
|
||||
bucketSize = MAXALIGN(bucketSize);
|
||||
|
||||
tmpBucket = (ELEMENT *)
|
||||
hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
|
||||
tmpBucket = (ELEMENT *) hashp->alloc(BUCKET_ALLOC_INCR * bucketSize);
|
||||
|
||||
if (!tmpBucket)
|
||||
return 0;
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
# Makefile for utils/init
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.13 2000/05/29 05:45:32 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.14 2000/06/28 03:32:43 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SRCDIR = ../../..
|
||||
include ../../../Makefile.global
|
||||
|
||||
OBJS = enbl.o findbe.o globals.o miscinit.o postinit.o
|
||||
OBJS = findbe.o globals.o miscinit.o postinit.o
|
||||
|
||||
all: SUBSYS.o
|
||||
|
||||
|
@ -27,4 +27,3 @@ clean:
|
|||
ifeq (depend,$(wildcard depend))
|
||||
include depend
|
||||
endif
|
||||
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* enbl.c
|
||||
* POSTGRES module enable and disable support code.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/enbl.c,v 1.10 2000/01/26 05:57:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
#include "utils/module.h"
|
||||
|
||||
/*
|
||||
* BypassEnable
|
||||
* False iff enable/disable processing is required given on and "*countP."
|
||||
*
|
||||
* Note:
|
||||
* As a side-effect, *countP is modified. It should be 0 initially.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called with pointer to value 0 and false.
|
||||
* BadArg if "countP" is invalid pointer.
|
||||
* BadArg if on is invalid.
|
||||
*/
|
||||
bool
|
||||
BypassEnable(int *enableCountInOutP, bool on)
|
||||
{
|
||||
AssertArg(PointerIsValid(enableCountInOutP));
|
||||
AssertArg(BoolIsValid(on));
|
||||
|
||||
if (on)
|
||||
{
|
||||
*enableCountInOutP += 1;
|
||||
return (bool) (*enableCountInOutP >= 2);
|
||||
}
|
||||
|
||||
Assert(*enableCountInOutP >= 1);
|
||||
|
||||
*enableCountInOutP -= 1;
|
||||
|
||||
return (bool) (*enableCountInOutP >= 1);
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.59 2000/05/30 00:49:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.60 2000/06/28 03:32:43 tgl Exp $
|
||||
*
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
|
@ -40,8 +40,6 @@
|
|||
#include "mb/pg_wchar.h"
|
||||
#endif
|
||||
|
||||
void BaseInit(void);
|
||||
|
||||
static void ReverifyMyDatabase(const char *name);
|
||||
static void InitCommunication(void);
|
||||
|
||||
|
@ -222,8 +220,6 @@ InitCommunication()
|
|||
* Be very careful with the order of calls in the InitPostgres function.
|
||||
* --------------------------------
|
||||
*/
|
||||
extern int NBuffers;
|
||||
|
||||
int lockingOff = 0; /* backend -L switch */
|
||||
|
||||
/*
|
||||
|
@ -405,21 +401,6 @@ InitPostgres(const char *dbname)
|
|||
void
|
||||
BaseInit(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Turn on the exception handler. Note: we cannot use elog, Assert,
|
||||
* AssertState, etc. until after exception handling is on.
|
||||
*/
|
||||
EnableExceptionHandling(true);
|
||||
|
||||
/*
|
||||
* Memory system initialization - we may call palloc after
|
||||
* EnableMemoryContext()). Note that EnableMemoryContext() must
|
||||
* happen before EnablePortalManager().
|
||||
*/
|
||||
EnableMemoryContext(true); /* initializes the "top context" */
|
||||
EnablePortalManager(true); /* memory for portal/transaction stuff */
|
||||
|
||||
/*
|
||||
* Attach to shared memory and semaphores, and initialize our
|
||||
* input/output/debugging file descriptors.
|
||||
|
@ -427,4 +408,6 @@ BaseInit(void)
|
|||
InitCommunication();
|
||||
DebugFileOpen();
|
||||
smgrinit();
|
||||
|
||||
EnablePortalManager(); /* memory for portal/transaction stuff */
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* WIN1250 client encoding support contributed by Pavel Behal
|
||||
* SJIS UDC (NEC selection IBM kanji) support contributed by Eiji Tokuya
|
||||
*
|
||||
* $Id: conv.c,v 1.15 2000/05/20 13:12:26 ishii Exp $
|
||||
* $Id: conv.c,v 1.16 2000/06/28 03:32:45 tgl Exp $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
@ -1521,7 +1521,8 @@ pg_encoding_conv_tbl pg_conv_tbl[] = {
|
|||
};
|
||||
|
||||
#ifdef DEBUGMAIN
|
||||
#include "utils/mcxt.h"
|
||||
#include "postgres.h"
|
||||
#include "utils/memutils.h"
|
||||
/*
|
||||
* testing for sjis2mic() and mic2sjis()
|
||||
*/
|
||||
|
@ -1565,21 +1566,23 @@ main()
|
|||
void
|
||||
elog(int lev, const char *fmt,...)
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
MemoryContext CurrentMemoryContext;
|
||||
Pointer
|
||||
|
||||
void *
|
||||
MemoryContextAlloc(MemoryContext context, Size size)
|
||||
{
|
||||
};
|
||||
Pointer
|
||||
MemoryContextRealloc(MemoryContext context,
|
||||
Pointer pointer,
|
||||
Size size)
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
MemoryContextFree(MemoryContext context, Pointer pointer)
|
||||
pfree(void *pointer)
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
void *
|
||||
repalloc(void *pointer, Size size)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
# Makefile for utils/mmgr
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.8 2000/05/29 05:45:40 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.9 2000/06/28 03:32:50 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SRCDIR = ../../..
|
||||
include ../../../Makefile.global
|
||||
|
||||
OBJS = aset.o mcxt.o palloc.o portalmem.o oset.o
|
||||
OBJS = aset.o mcxt.o portalmem.o
|
||||
|
||||
all: SUBSYS.o
|
||||
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
Proposal for memory allocation fixes, take 2 21-Jun-2000
|
||||
--------------------------------------------
|
||||
|
||||
We know that Postgres has serious problems with memory leakage during
|
||||
large queries that process a lot of pass-by-reference data. There is
|
||||
no provision for recycling memory until end of query. This needs to be
|
||||
fixed, even more so with the advent of TOAST which will allow very large
|
||||
chunks of data to be passed around in the system. So, here is a proposal.
|
||||
|
||||
|
||||
Background
|
||||
----------
|
||||
|
||||
We already do most of our memory allocation in "memory contexts", which
|
||||
are usually AllocSets as implemented by backend/utils/mmgr/aset.c. What
|
||||
we need to do is create more contexts and define proper rules about when
|
||||
they can be freed.
|
||||
|
||||
The basic operations on a memory context are:
|
||||
|
||||
* create a context
|
||||
|
||||
* allocate a chunk of memory within a context (equivalent of standard
|
||||
C library's malloc())
|
||||
|
||||
* delete a context (including freeing all the memory allocated therein)
|
||||
|
||||
* reset a context (free all memory allocated in the context, but not the
|
||||
context object itself)
|
||||
|
||||
Given a chunk of memory previously allocated from a context, one can
|
||||
free it or reallocate it larger or smaller (corresponding to standard
|
||||
library's free() and realloc() routines). These operations return memory
|
||||
to or get more memory from the same context the chunk was originally
|
||||
allocated in.
|
||||
|
||||
At all times there is a "current" context denoted by the
|
||||
CurrentMemoryContext global variable. The backend macro palloc()
|
||||
implicitly allocates space in that context. The MemoryContextSwitchTo()
|
||||
operation selects a new current context (and returns the previous context,
|
||||
so that the caller can restore the previous context before exiting).
|
||||
|
||||
The main advantage of memory contexts over plain use of malloc/free is
|
||||
that the entire contents of a memory context can be freed easily, without
|
||||
having to request freeing of each individual chunk within it. This is
|
||||
both faster and more reliable than per-chunk bookkeeping. We already use
|
||||
this fact to clean up at transaction end: by resetting all the active
|
||||
contexts, we reclaim all memory. What we need are additional contexts
|
||||
that can be reset or deleted at strategic times within a query, such as
|
||||
after each tuple.
|
||||
|
||||
|
||||
pfree/repalloc no longer depend on CurrentMemoryContext
|
||||
-------------------------------------------------------
|
||||
|
||||
In this proposal, pfree() and repalloc() can be applied to any chunk
|
||||
whether it belongs to CurrentMemoryContext or not --- the chunk's owning
|
||||
context will be invoked to handle the operation, regardless. This is a
|
||||
change from the old requirement that CurrentMemoryContext must be set
|
||||
to the same context the memory was allocated from before one can use
|
||||
pfree() or repalloc(). The old coding requirement is obviously fairly
|
||||
error-prone, and will become more so the more context-switching we do;
|
||||
so I think it's essential to use CurrentMemoryContext only for palloc.
|
||||
We can avoid needing it for pfree/repalloc by putting restrictions on
|
||||
context managers as discussed below.
|
||||
|
||||
We could even consider getting rid of CurrentMemoryContext entirely,
|
||||
instead requiring the target memory context for allocation to be specified
|
||||
explicitly. But I think that would be too much notational overhead ---
|
||||
we'd have to pass an apppropriate memory context to called routines in
|
||||
many places. For example, the copyObject routines would need to be passed
|
||||
a context, as would function execution routines that return a
|
||||
pass-by-reference datatype. And what of routines that temporarily
|
||||
allocate space internally, but don't return it to their caller? We
|
||||
certainly don't want to clutter every call in the system with "here is
|
||||
a context to use for any temporary memory allocation you might want to
|
||||
do". So there'd still need to be a global variable specifying a suitable
|
||||
temporary-allocation context. That might as well be CurrentMemoryContext.
|
||||
|
||||
|
||||
Additions to the memory-context mechanism
|
||||
-----------------------------------------
|
||||
|
||||
If we are going to have more contexts, we need more mechanism for keeping
|
||||
track of them; else we risk leaking whole contexts under error conditions.
|
||||
|
||||
We can do this by creating trees of "parent" and "child" contexts. When
|
||||
creating a memory context, the new context can be specified to be a child
|
||||
of some existing context. A context can have many children, but only one
|
||||
parent. In this way the contexts form a forest (not necessarily a single
|
||||
tree, since there could be more than one top-level context).
|
||||
|
||||
We then say that resetting or deleting any particular context resets or
|
||||
deletes all its direct and indirect children as well. This feature allows
|
||||
us to manage a lot of contexts without fear that some will be leaked; we
|
||||
only need to keep track of one top-level context that we are going to
|
||||
delete at transaction end, and make sure that any shorter-lived contexts
|
||||
we create are descendants of that context. Since the tree can have
|
||||
multiple levels, we can deal easily with nested lifetimes of storage,
|
||||
such as per-transaction, per-statement, per-scan, per-tuple. Storage
|
||||
lifetimes that only partially overlap can be handled by allocating
|
||||
from different trees of the context forest (there are some examples
|
||||
in the next section).
|
||||
|
||||
For convenience we will also want operations like "reset/delete all
|
||||
children of a given context, but don't reset or delete that context
|
||||
itself".
|
||||
|
||||
|
||||
Top-level contexts
|
||||
------------------
|
||||
|
||||
There will be several top-level contexts --- these contexts have no parent
|
||||
and will be referenced by global variables. At any instant the system may
|
||||
contain many additional contexts, but all other contexts should be direct
|
||||
or indirect children of one of the top-level contexts to ensure they are
|
||||
not leaked in event of an error. I presently envision these top-level
|
||||
contexts:
|
||||
|
||||
TopMemoryContext --- allocating here is essentially the same as "malloc",
|
||||
because this context will never be reset or deleted. This is for stuff
|
||||
that should live forever, or for stuff that you know you will delete
|
||||
at the appropriate time. An example is fd.c's tables of open files,
|
||||
as well as the context management nodes for memory contexts themselves.
|
||||
Avoid allocating stuff here unless really necessary, and especially
|
||||
avoid running with CurrentMemoryContext pointing here.
|
||||
|
||||
PostmasterContext --- this is the postmaster's normal working context.
|
||||
After a backend is spawned, it can delete PostmasterContext to free its
|
||||
copy of memory the postmaster was using that it doesn't need. (Anything
|
||||
that has to be passed from postmaster to backends will be passed in
|
||||
TopMemoryContext. The postmaster will probably have only TopMemoryContext,
|
||||
PostmasterContext, and possibly ErrorContext --- the remaining top-level
|
||||
contexts will be set up in each backend during startup.)
|
||||
|
||||
CacheMemoryContext --- permanent storage for relcache, catcache, and
|
||||
related modules. This will never be reset or deleted, either, so it's
|
||||
not truly necessary to distinguish it from TopMemoryContext. But it
|
||||
seems worthwhile to maintain the distinction for debugging purposes.
|
||||
(Note: CacheMemoryContext may well have child-contexts with shorter
|
||||
lifespans. For example, a child context seems like the best place to
|
||||
keep the subsidiary storage associated with a relcache entry; that way
|
||||
we can free rule parsetrees and so forth easily, without having to depend
|
||||
on constructing a reliable version of freeObject().)
|
||||
|
||||
QueryContext --- this is where the storage holding a received query string
|
||||
is kept, as well as storage that should live as long as the query string,
|
||||
notably the parsetree constructed from it. This context will be reset at
|
||||
the top of each cycle of the outer loop of PostgresMain, thereby freeing
|
||||
the old query and parsetree. We must keep this separate from
|
||||
TopTransactionContext because a query string might need to live either a
|
||||
longer or shorter time than a transaction, depending on whether it
|
||||
contains begin/end commands or not. (This'll also fix the nasty bug that
|
||||
"vacuum; anything else" crashes if submitted as a single query string,
|
||||
because vacuum's xact commit frees the memory holding the parsetree...)
|
||||
|
||||
TopTransactionContext --- this holds everything that lives until end of
|
||||
transaction (longer than one statement within a transaction!). An example
|
||||
of what has to be here is the list of pending NOTIFY messages to be sent
|
||||
at xact commit. This context will be reset, and all its children deleted,
|
||||
at conclusion of each transaction cycle. Note: presently I envision that
|
||||
this context will NOT be cleared immediately upon error; its contents
|
||||
will survive anyway until the transaction block is exited by
|
||||
COMMIT/ROLLBACK. This seems appropriate since we want to move in the
|
||||
direction of allowing a transaction to continue processing after an error.
|
||||
|
||||
TransactionCommandContext --- this is really a child of
|
||||
TopTransactionContext, not a top-level context, but we'll probably store a
|
||||
link to it in a global variable anyway for convenience. All the memory
|
||||
allocated during planning and execution lives here or in a child context.
|
||||
This context is deleted at statement completion, whether normal completion
|
||||
or error abort.
|
||||
|
||||
ErrorContext --- this permanent context will be switched into
|
||||
for error recovery processing, and then reset on completion of recovery.
|
||||
We'll arrange to have, say, 8K of memory available in it at all times.
|
||||
In this way, we can ensure that some memory is available for error
|
||||
recovery even if the backend has run out of memory otherwise. This should
|
||||
allow out-of-memory to be treated as a normal ERROR condition, not a FATAL
|
||||
error.
|
||||
|
||||
If we ever implement nested transactions, there may need to be some
|
||||
additional levels of transaction-local contexts between
|
||||
TopTransactionContext and TransactionCommandContext, but that's beyond
|
||||
the scope of this proposal.
|
||||
|
||||
|
||||
Transient contexts during execution
|
||||
-----------------------------------
|
||||
|
||||
The planner will probably have a transient context in which it stores
|
||||
pathnodes; this will allow it to release the bulk of its temporary space
|
||||
usage (which can be a lot, for large joins) at completion of planning.
|
||||
The completed plan tree will be in TransactionCommandContext.
|
||||
|
||||
The executor will have contexts with lifetime similar to plan nodes
|
||||
(I'm not sure at the moment whether there's need for one such context
|
||||
per plan level, or whether a single context is sufficient). These
|
||||
contexts will hold plan-node-local execution state and related items.
|
||||
There will also be a context on each plan level that is reset at the start
|
||||
of each tuple processing cycle. This per-tuple context will be the normal
|
||||
CurrentMemoryContext during evaluation of expressions and so forth. By
|
||||
resetting it, we reclaim transient memory that was used during processing
|
||||
of the prior tuple. That should be enough to solve the problem of running
|
||||
out of memory on large queries. We must have a per-tuple context in each
|
||||
plan node, and we must reset it at the start of a tuple cycle rather than
|
||||
the end, so that each plan node can use results of expression evaluation
|
||||
as part of the tuple it returns to its parent node.
|
||||
|
||||
By resetting the per-tuple context, we will be able to free memory after
|
||||
each tuple is processed, rather than only after the whole plan is
|
||||
processed. This should solve our memory leakage problems pretty well;
|
||||
yet we do not need to add very much new bookkeeping logic to do it.
|
||||
In particular, we do *not* need to try to keep track of individual values
|
||||
palloc'd during expression evaluation.
|
||||
|
||||
Note we assume that resetting a context is a cheap operation. This is
|
||||
true already, and we can make it even more true with a little bit of
|
||||
tuning in aset.c.
|
||||
|
||||
There will be some special cases, such as aggregate functions. nodeAgg.c
|
||||
needs to remember the results of evaluation of aggregate transition
|
||||
functions from one tuple cycle to the next, so it can't just discard
|
||||
all per-tuple state in each cycle. The easiest way to handle this seems
|
||||
to be to have two per-tuple contexts in an aggregate node, and to
|
||||
ping-pong between them, so that at each tuple one is the active allocation
|
||||
context and the other holds any results allocated by the prior cycle's
|
||||
transition function.
|
||||
|
||||
Executor routines that switch the active CurrentMemoryContext may need
|
||||
to copy data into their caller's current memory context before returning.
|
||||
I think there will be relatively little need for that, because of the
|
||||
convention of resetting the per-tuple context at the *start* of an
|
||||
execution cycle rather than at its end. With that rule, an execution
|
||||
node can return a tuple that is palloc'd in its per-tuple context, and
|
||||
the tuple will remain good until the node is called for another tuple
|
||||
or told to end execution. This is pretty much the same state of affairs
|
||||
that exists now, since a scan node can return a direct pointer to a tuple
|
||||
in a disk buffer that is only guaranteed to remain good that long.
|
||||
|
||||
A more common reason for copying data will be to transfer a result from
|
||||
per-tuple context to per-run context; for example, a Unique node will
|
||||
save the last distinct tuple value in its per-run context, requiring a
|
||||
copy step. (Actually, Unique could use the same trick with two per-tuple
|
||||
contexts as described above for Agg, but there will probably be other
|
||||
cases where doing an extra copy step is the right thing.)
|
||||
|
||||
Another interesting special case is VACUUM, which needs to allocate
|
||||
working space that will survive its forced transaction commits, yet
|
||||
be released on error. Currently it does that through a "portal",
|
||||
which is essentially a child context of TopMemoryContext. While that
|
||||
way still works, it's ugly since xact abort needs special processing
|
||||
to delete the portal. Better would be to use a context that's a child
|
||||
of QueryContext and hence is certain to go away as part of normal
|
||||
processing. (Eventually we might have an even better solution from
|
||||
nested transactions, but this'll do fine for now.)
|
||||
|
||||
|
||||
Mechanisms to allow multiple types of contexts
|
||||
----------------------------------------------
|
||||
|
||||
We may want several different types of memory contexts with different
|
||||
allocation policies but similar external behavior. To handle this,
|
||||
memory allocation functions will be accessed via function pointers,
|
||||
and we will require all context types to obey the conventions given here.
|
||||
(This is not very far different from the existing code.)
|
||||
|
||||
A memory context will be represented by an object like
|
||||
|
||||
typedef struct MemoryContextData
|
||||
{
|
||||
NodeTag type; /* identifies exact kind of context */
|
||||
MemoryContextMethods methods;
|
||||
MemoryContextData *parent; /* NULL if no parent (toplevel context) */
|
||||
MemoryContextData *firstchild; /* head of linked list of children */
|
||||
MemoryContextData *nextchild; /* next child of same parent */
|
||||
char *name; /* context name (just for debugging) */
|
||||
} MemoryContextData, *MemoryContext;
|
||||
|
||||
This is essentially an abstract superclass, and the "methods" pointer is
|
||||
its virtual function table. Specific memory context types will use
|
||||
derived structs having these fields as their first fields. All the
|
||||
contexts of a specific type will have methods pointers that point to the
|
||||
same static table of function pointers, which will look like
|
||||
|
||||
typedef struct MemoryContextMethodsData
|
||||
{
|
||||
Pointer (*alloc) (MemoryContext c, Size size);
|
||||
void (*free_p) (Pointer chunk);
|
||||
Pointer (*realloc) (Pointer chunk, Size newsize);
|
||||
void (*reset) (MemoryContext c);
|
||||
void (*delete) (MemoryContext c);
|
||||
} MemoryContextMethodsData, *MemoryContextMethods;
|
||||
|
||||
Alloc, reset, and delete requests will take a MemoryContext pointer
|
||||
as parameter, so they'll have no trouble finding the method pointer
|
||||
to call. Free and realloc are trickier. To make those work, we will
|
||||
require all memory context types to produce allocated chunks that
|
||||
are immediately preceded by a standard chunk header, which has the
|
||||
layout
|
||||
|
||||
typedef struct StandardChunkHeader
|
||||
{
|
||||
MemoryContext mycontext; /* Link to owning context object */
|
||||
Size size; /* Allocated size of chunk */
|
||||
};
|
||||
|
||||
It turns out that the existing aset.c memory context type does this
|
||||
already, and probably any other kind of context would need to have the
|
||||
same data available to support realloc, so this is not really creating
|
||||
any additional overhead. (Note that if a context type needs more per-
|
||||
allocated-chunk information than this, it can make an additional
|
||||
nonstandard header that precedes the standard header. So we're not
|
||||
constraining context-type designers very much.)
|
||||
|
||||
Given this, the pfree routine will look something like
|
||||
|
||||
StandardChunkHeader * header =
|
||||
(StandardChunkHeader *) ((char *) p - sizeof(StandardChunkHeader));
|
||||
|
||||
(*header->mycontext->methods->free_p) (p);
|
||||
|
||||
We could do it as a macro, but the macro would have to evaluate its
|
||||
argument twice, which seems like a bad idea (the current pfree macro
|
||||
does not do that). This is already saving two levels of function call
|
||||
compared to the existing code, so I think we're doing fine without
|
||||
squeezing out that last little bit ...
|
||||
|
||||
|
||||
More control over aset.c behavior
|
||||
---------------------------------
|
||||
|
||||
Currently, aset.c allocates an 8K block upon the first allocation in
|
||||
a context, and doubles that size for each successive block request.
|
||||
That's good behavior for a context that might hold *lots* of data, and
|
||||
the overhead wasn't bad when we had only a few contexts in existence.
|
||||
With dozens if not hundreds of smaller contexts in the system, we will
|
||||
want to be able to fine-tune things a little better.
|
||||
|
||||
The creator of a context will be able to specify an initial block size
|
||||
and a maximum block size. Selecting smaller values will prevent wastage
|
||||
of space in contexts that aren't expected to hold very much (an example is
|
||||
the relcache's per-relation contexts).
|
||||
|
||||
Also, it will be possible to specify a minimum context size. If this
|
||||
value is greater than zero then a block of that size will be grabbed
|
||||
immediately upon context creation, and cleared but not released during
|
||||
context resets. This feature is needed for ErrorContext (see above).
|
||||
It is also useful for per-tuple contexts, which will be reset frequently
|
||||
and typically will not allocate very much space per tuple cycle. We can
|
||||
save a lot of unnecessary malloc traffic if these contexts hang onto one
|
||||
allocation block rather than releasing and reacquiring the block on
|
||||
each tuple cycle.
|
||||
|
||||
|
||||
Other notes
|
||||
-----------
|
||||
|
||||
The original version of this proposal suggested that functions returning
|
||||
pass-by-reference datatypes should be required to return a value freshly
|
||||
palloc'd in their caller's memory context, never a pointer to an input
|
||||
value. I've abandoned that notion since it clearly is prone to error.
|
||||
In the current proposal, it is possible to discover which context a
|
||||
chunk of memory is allocated in (by checking the required standard chunk
|
||||
header), so nodeAgg can determine whether or not it's safe to reset
|
||||
its working context; it doesn't have to rely on the transition function
|
||||
to do what it's expecting.
|
||||
|
||||
It might be that the executor per-run contexts described above should
|
||||
be tied directly to executor "EState" nodes, that is, one context per
|
||||
EState. I'm not real clear on the lifespan of EStates or the situations
|
||||
where we have just one or more than one, so I'm not sure. Comments?
|
||||
|
||||
It would probably be possible to adapt the existing "portal" memory
|
||||
management mechanism to do what we need. I am instead proposing setting
|
||||
up a totally new mechanism, because the portal code strikes me as
|
||||
extremely crufty and unwieldy. It may be that we can eventually remove
|
||||
portals entirely, or perhaps reimplement them with this mechanism
|
||||
underneath.
|
|
@ -3,12 +3,15 @@
|
|||
* aset.c
|
||||
* Allocation set definitions.
|
||||
*
|
||||
* AllocSet is our standard implementation of the abstract MemoryContext
|
||||
* type.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.27 2000/05/21 02:23:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.28 2000/06/28 03:32:50 tgl Exp $
|
||||
*
|
||||
* NOTE:
|
||||
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
||||
|
@ -30,15 +33,68 @@
|
|||
* AllocSetReset() under the old way.
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "utils/memutils.h"
|
||||
|
||||
|
||||
#undef AllocSetReset
|
||||
#undef malloc
|
||||
#undef free
|
||||
#undef realloc
|
||||
/*
|
||||
* AllocSetContext is defined in nodes/memnodes.h.
|
||||
*/
|
||||
typedef AllocSetContext *AllocSet;
|
||||
|
||||
/*
|
||||
* AllocPointer
|
||||
* Aligned pointer which may be a member of an allocation set.
|
||||
*/
|
||||
typedef void *AllocPointer;
|
||||
|
||||
/*
|
||||
* AllocBlock
|
||||
* An AllocBlock is the unit of memory that is obtained by aset.c
|
||||
* from malloc(). It contains one or more AllocChunks, which are
|
||||
* the units requested by palloc() and freed by pfree(). AllocChunks
|
||||
* cannot be returned to malloc() individually, instead they are put
|
||||
* on freelists by pfree() and re-used by the next palloc() that has
|
||||
* a matching request size.
|
||||
*
|
||||
* AllocBlockData is the header data for a block --- the usable space
|
||||
* within the block begins at the next alignment boundary.
|
||||
*/
|
||||
typedef struct AllocBlockData
|
||||
{
|
||||
AllocSet aset; /* aset that owns this block */
|
||||
AllocBlock next; /* next block in aset's blocks list */
|
||||
char *freeptr; /* start of free space in this block */
|
||||
char *endptr; /* end of space in this block */
|
||||
} AllocBlockData;
|
||||
|
||||
/*
|
||||
* AllocChunk
|
||||
* The prefix of each piece of memory in an AllocBlock
|
||||
*
|
||||
* NB: this MUST match StandardChunkHeader as defined by utils/memutils.h.
|
||||
*/
|
||||
typedef struct AllocChunkData
|
||||
{
|
||||
/* aset is the owning aset if allocated, or the freelist link if free */
|
||||
void *aset;
|
||||
/* size is always the size of the usable space in the chunk */
|
||||
Size size;
|
||||
} AllocChunkData;
|
||||
|
||||
/*
|
||||
* AllocPointerIsValid
|
||||
* True iff pointer is valid allocation pointer.
|
||||
*/
|
||||
#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
|
||||
|
||||
/*
|
||||
* AllocSetIsValid
|
||||
* True iff set is valid allocation set.
|
||||
*/
|
||||
#define AllocSetIsValid(set) PointerIsValid(set)
|
||||
|
||||
/*--------------------
|
||||
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
|
||||
|
@ -59,9 +115,9 @@
|
|||
/* Size of largest chunk that we use a fixed size for */
|
||||
|
||||
/*--------------------
|
||||
* The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
|
||||
* The first block allocated for an allocset has size initBlockSize.
|
||||
* Each time we have to allocate another block, we double the block size
|
||||
* (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
|
||||
* (if possible, and without exceeding maxBlockSize), so as to reduce
|
||||
* the bookkeeping load on malloc().
|
||||
*
|
||||
* Blocks allocated to hold oversize chunks do not follow this rule, however;
|
||||
|
@ -74,20 +130,21 @@
|
|||
* AllocSetAlloc has discretion whether to put the request into an existing
|
||||
* block or make a single-chunk block.
|
||||
*
|
||||
* We must have ALLOC_MIN_BLOCK_SIZE > ALLOC_SMALLCHUNK_LIMIT and
|
||||
* We must have initBlockSize > ALLOC_SMALLCHUNK_LIMIT and
|
||||
* ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
|
||||
*--------------------
|
||||
*/
|
||||
|
||||
#define ALLOC_MIN_BLOCK_SIZE (8 * 1024)
|
||||
#define ALLOC_MAX_BLOCK_SIZE (8 * 1024 * 1024)
|
||||
|
||||
#define ALLOC_BIGCHUNK_LIMIT (64 * 1024)
|
||||
/* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
|
||||
|
||||
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
|
||||
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
|
||||
|
||||
/* Min safe value of allocation block size */
|
||||
#define ALLOC_MIN_BLOCK_SIZE \
|
||||
(ALLOC_SMALLCHUNK_LIMIT + ALLOC_CHUNKHDRSZ + ALLOC_BLOCKHDRSZ)
|
||||
|
||||
#define AllocPointerGetChunk(ptr) \
|
||||
((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
|
||||
#define AllocChunkGetPointer(chk) \
|
||||
|
@ -95,6 +152,29 @@
|
|||
#define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
|
||||
#define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size)
|
||||
|
||||
/*
|
||||
* These functions implement the MemoryContext API for AllocSet contexts.
|
||||
*/
|
||||
static void *AllocSetAlloc(MemoryContext context, Size size);
|
||||
static void AllocSetFree(MemoryContext context, void *pointer);
|
||||
static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
|
||||
static void AllocSetInit(MemoryContext context);
|
||||
static void AllocSetReset(MemoryContext context);
|
||||
static void AllocSetDelete(MemoryContext context);
|
||||
static void AllocSetStats(MemoryContext context);
|
||||
|
||||
/*
|
||||
* This is the virtual function table for AllocSet contexts.
|
||||
*/
|
||||
static MemoryContextMethods AllocSetMethods = {
|
||||
AllocSetAlloc,
|
||||
AllocSetFree,
|
||||
AllocSetRealloc,
|
||||
AllocSetInit,
|
||||
AllocSetReset,
|
||||
AllocSetDelete,
|
||||
AllocSetStats
|
||||
};
|
||||
|
||||
|
||||
/* ----------
|
||||
|
@ -127,52 +207,159 @@ AllocSetFreeIndex(Size size)
|
|||
* Public routines
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* AllocSetInit
|
||||
* Initializes given allocation set.
|
||||
* AllocSetContextCreate
|
||||
* Create a new AllocSet context.
|
||||
*
|
||||
* Note:
|
||||
* The semantics of the mode are explained above. Limit is ignored
|
||||
* for dynamic and static modes.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if set is invalid pointer.
|
||||
* BadArg if mode is invalid.
|
||||
* parent: parent context, or NULL if top-level context
|
||||
* name: name of context (for debugging --- string will be copied)
|
||||
* minContextSize: minimum context size
|
||||
* initBlockSize: initial allocation block size
|
||||
* maxBlockSize: maximum allocation block size
|
||||
*/
|
||||
void
|
||||
AllocSetInit(AllocSet set, AllocMode mode, Size limit)
|
||||
MemoryContext
|
||||
AllocSetContextCreate(MemoryContext parent,
|
||||
const char *name,
|
||||
Size minContextSize,
|
||||
Size initBlockSize,
|
||||
Size maxBlockSize)
|
||||
{
|
||||
AssertArg(PointerIsValid(set));
|
||||
AssertArg((int) DynamicAllocMode <= (int) mode);
|
||||
AssertArg((int) mode <= (int) BoundedAllocMode);
|
||||
AllocSet context;
|
||||
|
||||
/* Do the type-independent part of context creation */
|
||||
context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
|
||||
sizeof(AllocSetContext),
|
||||
&AllocSetMethods,
|
||||
parent,
|
||||
name);
|
||||
/*
|
||||
* Make sure alloc parameters are safe, and save them
|
||||
*/
|
||||
initBlockSize = MAXALIGN(initBlockSize);
|
||||
if (initBlockSize < ALLOC_MIN_BLOCK_SIZE)
|
||||
initBlockSize = ALLOC_MIN_BLOCK_SIZE;
|
||||
maxBlockSize = MAXALIGN(maxBlockSize);
|
||||
if (maxBlockSize < initBlockSize)
|
||||
maxBlockSize = initBlockSize;
|
||||
context->initBlockSize = initBlockSize;
|
||||
context->maxBlockSize = maxBlockSize;
|
||||
|
||||
/*
|
||||
* XXX mode is currently ignored and treated as DynamicAllocMode. XXX
|
||||
* limit is also ignored. This affects this whole file.
|
||||
* Grab always-allocated space, if requested
|
||||
*/
|
||||
if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)
|
||||
{
|
||||
Size blksize = MAXALIGN(minContextSize);
|
||||
AllocBlock block;
|
||||
|
||||
memset(set, 0, sizeof(AllocSetData));
|
||||
block = (AllocBlock) malloc(blksize);
|
||||
if (block == NULL)
|
||||
elog(ERROR, "Memory exhausted in AllocSetContextCreate()");
|
||||
block->aset = context;
|
||||
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
|
||||
block->endptr = ((char *) block) + blksize;
|
||||
block->next = context->blocks;
|
||||
context->blocks = block;
|
||||
/* Mark block as not to be released at reset time */
|
||||
context->keeper = block;
|
||||
}
|
||||
|
||||
return (MemoryContext) context;
|
||||
}
|
||||
|
||||
/*
|
||||
* AllocSetInit
|
||||
* Context-type-specific initialization routine.
|
||||
*
|
||||
* This is called by MemoryContextCreate() after setting up the
|
||||
* generic MemoryContext fields and before linking the new context
|
||||
* into the context tree. We must do whatever is needed to make the
|
||||
* new context minimally valid for deletion. We must *not* risk
|
||||
* failure --- thus, for example, allocating more memory is not cool.
|
||||
* (AllocSetContextCreate can allocate memory when it gets control
|
||||
* back, however.)
|
||||
*/
|
||||
static void
|
||||
AllocSetInit(MemoryContext context)
|
||||
{
|
||||
/*
|
||||
* Since MemoryContextCreate already zeroed the context node,
|
||||
* we don't have to do anything here: it's already OK.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* AllocSetReset
|
||||
* Frees all memory which is allocated in the given set.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if set is invalid.
|
||||
* Actually, this routine has some discretion about what to do.
|
||||
* It should mark all allocated chunks freed, but it need not
|
||||
* necessarily give back all the resources the set owns. Our
|
||||
* actual implementation is that we hang on to any "keeper"
|
||||
* block specified for the set.
|
||||
*/
|
||||
void
|
||||
AllocSetReset(AllocSet set)
|
||||
static void
|
||||
AllocSetReset(MemoryContext context)
|
||||
{
|
||||
AllocSet set = (AllocSet) context;
|
||||
AllocBlock block = set->blocks;
|
||||
AllocBlock next;
|
||||
|
||||
AssertArg(AllocSetIsValid(set));
|
||||
|
||||
while (block != NULL)
|
||||
{
|
||||
next = block->next;
|
||||
AllocBlock next = block->next;
|
||||
|
||||
if (block == set->keeper)
|
||||
{
|
||||
/* Reset the block, but don't return it to malloc */
|
||||
block->next = NULL;
|
||||
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
|
||||
#ifdef CLOBBER_FREED_MEMORY
|
||||
/* Wipe freed memory for debugging purposes */
|
||||
memset(block->freeptr, 0x7F,
|
||||
((char *) block->endptr) - ((char *) block->freeptr));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal case, release the block */
|
||||
#ifdef CLOBBER_FREED_MEMORY
|
||||
/* Wipe freed memory for debugging purposes */
|
||||
memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
|
||||
#endif
|
||||
free(block);
|
||||
}
|
||||
block = next;
|
||||
}
|
||||
|
||||
/* Now blocks list is either empty or just the keeper block */
|
||||
set->blocks = set->keeper;
|
||||
/* Clear chunk freelists in any case */
|
||||
MemSet(set->freelist, 0, sizeof(set->freelist));
|
||||
}
|
||||
|
||||
/*
|
||||
* AllocSetDelete
|
||||
* Frees all memory which is allocated in the given set,
|
||||
* in preparation for deletion of the set.
|
||||
*
|
||||
* Unlike AllocSetReset, this *must* free all resources of the set.
|
||||
* But note we are not responsible for deleting the context node itself.
|
||||
*/
|
||||
static void
|
||||
AllocSetDelete(MemoryContext context)
|
||||
{
|
||||
AllocSet set = (AllocSet) context;
|
||||
AllocBlock block = set->blocks;
|
||||
|
||||
AssertArg(AllocSetIsValid(set));
|
||||
|
||||
while (block != NULL)
|
||||
{
|
||||
AllocBlock next = block->next;
|
||||
|
||||
#ifdef CLOBBER_FREED_MEMORY
|
||||
/* Wipe freed memory for debugging purposes */
|
||||
memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
|
||||
|
@ -181,38 +368,21 @@ AllocSetReset(AllocSet set)
|
|||
block = next;
|
||||
}
|
||||
|
||||
memset(set, 0, sizeof(AllocSetData));
|
||||
}
|
||||
|
||||
/*
|
||||
* AllocSetContains
|
||||
* True iff allocation set contains given allocation element.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if set is invalid.
|
||||
* BadArg if pointer is invalid.
|
||||
*/
|
||||
bool
|
||||
AllocSetContains(AllocSet set, AllocPointer pointer)
|
||||
{
|
||||
AssertArg(AllocSetIsValid(set));
|
||||
AssertArg(AllocPointerIsValid(pointer));
|
||||
|
||||
return (AllocPointerGetAset(pointer) == set);
|
||||
/* Make it look empty, just in case... */
|
||||
set->blocks = NULL;
|
||||
MemSet(set->freelist, 0, sizeof(set->freelist));
|
||||
set->keeper = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* AllocSetAlloc
|
||||
* Returns pointer to allocated memory of given size; memory is added
|
||||
* to the set.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if set is invalid.
|
||||
* MemoryExhausted if allocation fails.
|
||||
*/
|
||||
AllocPointer
|
||||
AllocSetAlloc(AllocSet set, Size size)
|
||||
static void *
|
||||
AllocSetAlloc(MemoryContext context, Size size)
|
||||
{
|
||||
AllocSet set = (AllocSet) context;
|
||||
AllocBlock block;
|
||||
AllocChunk chunk;
|
||||
AllocChunk priorfree = NULL;
|
||||
|
@ -225,7 +395,6 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||
/*
|
||||
* Lookup in the corresponding free list if there is a free chunk we
|
||||
* could reuse
|
||||
*
|
||||
*/
|
||||
fidx = AllocSetFreeIndex(size);
|
||||
for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
|
||||
|
@ -238,7 +407,6 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||
/*
|
||||
* If one is found, remove it from the free list, make it again a
|
||||
* member of the alloc set and return its data address.
|
||||
*
|
||||
*/
|
||||
if (chunk != NULL)
|
||||
{
|
||||
|
@ -284,7 +452,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
||||
block = (AllocBlock) malloc(blksize);
|
||||
if (block == NULL)
|
||||
elog(FATAL, "Memory exhausted in AllocSetAlloc()");
|
||||
elog(ERROR, "Memory exhausted in AllocSetAlloc()");
|
||||
block->aset = set;
|
||||
block->freeptr = block->endptr = ((char *) block) + blksize;
|
||||
|
||||
|
@ -317,7 +485,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||
{
|
||||
if (set->blocks == NULL)
|
||||
{
|
||||
blksize = ALLOC_MIN_BLOCK_SIZE;
|
||||
blksize = set->initBlockSize;
|
||||
block = (AllocBlock) malloc(blksize);
|
||||
}
|
||||
else
|
||||
|
@ -327,15 +495,18 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||
|
||||
/*
|
||||
* Special case: if very first allocation was for a large
|
||||
* chunk, could have a funny-sized top block. Do something
|
||||
* reasonable.
|
||||
* chunk (or we have a small "keeper" block), could have an
|
||||
* undersized top block. Do something reasonable.
|
||||
*/
|
||||
if (blksize < ALLOC_MIN_BLOCK_SIZE)
|
||||
blksize = ALLOC_MIN_BLOCK_SIZE;
|
||||
/* Crank it up, but not past max */
|
||||
blksize <<= 1;
|
||||
if (blksize > ALLOC_MAX_BLOCK_SIZE)
|
||||
blksize = ALLOC_MAX_BLOCK_SIZE;
|
||||
if (blksize < set->initBlockSize)
|
||||
blksize = set->initBlockSize;
|
||||
else
|
||||
{
|
||||
/* Crank it up, but not past max */
|
||||
blksize <<= 1;
|
||||
if (blksize > set->maxBlockSize)
|
||||
blksize = set->maxBlockSize;
|
||||
}
|
||||
/* Try to allocate it */
|
||||
block = (AllocBlock) malloc(blksize);
|
||||
|
||||
|
@ -352,7 +523,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||
}
|
||||
|
||||
if (block == NULL)
|
||||
elog(FATAL, "Memory exhausted in AllocSetAlloc()");
|
||||
elog(ERROR, "Memory exhausted in AllocSetAlloc()");
|
||||
block->aset = set;
|
||||
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
|
||||
block->endptr = ((char *) block) + blksize;
|
||||
|
@ -376,22 +547,12 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||
/*
|
||||
* AllocSetFree
|
||||
* Frees allocated memory; memory is removed from the set.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if set is invalid.
|
||||
* BadArg if pointer is invalid.
|
||||
* BadArg if pointer is not member of set.
|
||||
*/
|
||||
void
|
||||
AllocSetFree(AllocSet set, AllocPointer pointer)
|
||||
static void
|
||||
AllocSetFree(MemoryContext context, void *pointer)
|
||||
{
|
||||
AllocChunk chunk;
|
||||
|
||||
/* AssertArg(AllocSetIsValid(set)); */
|
||||
/* AssertArg(AllocPointerIsValid(pointer)); */
|
||||
AssertArg(AllocSetContains(set, pointer));
|
||||
|
||||
chunk = AllocPointerGetChunk(pointer);
|
||||
AllocSet set = (AllocSet) context;
|
||||
AllocChunk chunk = AllocPointerGetChunk(pointer);
|
||||
|
||||
#ifdef CLOBBER_FREED_MEMORY
|
||||
/* Wipe freed memory for debugging purposes */
|
||||
|
@ -446,24 +607,15 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
|
|||
* Returns new pointer to allocated memory of given size; this memory
|
||||
* is added to the set. Memory associated with given pointer is copied
|
||||
* into the new memory, and the old memory is freed.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if set is invalid.
|
||||
* BadArg if pointer is invalid.
|
||||
* BadArg if pointer is not member of set.
|
||||
* MemoryExhausted if allocation fails.
|
||||
*/
|
||||
AllocPointer
|
||||
AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
||||
static void *
|
||||
AllocSetRealloc(MemoryContext context, void *pointer, Size size)
|
||||
{
|
||||
AllocSet set = (AllocSet) context;
|
||||
Size oldsize;
|
||||
|
||||
/* AssertArg(AllocSetIsValid(set)); */
|
||||
/* AssertArg(AllocPointerIsValid(pointer)); */
|
||||
AssertArg(AllocSetContains(set, pointer));
|
||||
|
||||
/*
|
||||
* Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
|
||||
* Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
|
||||
* allocated area already is >= the new size. (In particular, we
|
||||
* always fall out here if the requested size is a decrease.)
|
||||
*/
|
||||
|
@ -503,7 +655,7 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
|||
blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
||||
block = (AllocBlock) realloc(block, blksize);
|
||||
if (block == NULL)
|
||||
elog(FATAL, "Memory exhausted in AllocSetReAlloc()");
|
||||
elog(ERROR, "Memory exhausted in AllocSetReAlloc()");
|
||||
block->freeptr = block->endptr = ((char *) block) + blksize;
|
||||
|
||||
/* Update pointers since block has likely been moved */
|
||||
|
@ -520,35 +672,26 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
|||
/* Normal small-chunk case: just do it by brute force. */
|
||||
|
||||
/* allocate new chunk */
|
||||
AllocPointer newPointer = AllocSetAlloc(set, size);
|
||||
AllocPointer newPointer = AllocSetAlloc((MemoryContext) set, size);
|
||||
|
||||
/* transfer existing data (certain to fit) */
|
||||
memcpy(newPointer, pointer, oldsize);
|
||||
|
||||
/* free old chunk */
|
||||
AllocSetFree(set, pointer);
|
||||
AllocSetFree((MemoryContext) set, pointer);
|
||||
|
||||
return newPointer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* AllocSetDump
|
||||
* Displays allocated set.
|
||||
*/
|
||||
void
|
||||
AllocSetDump(AllocSet set)
|
||||
{
|
||||
elog(DEBUG, "Currently unable to dump AllocSet");
|
||||
}
|
||||
|
||||
/*
|
||||
* AllocSetStats
|
||||
* Displays stats about memory consumption of an allocset.
|
||||
*/
|
||||
void
|
||||
AllocSetStats(AllocSet set, const char *ident)
|
||||
static void
|
||||
AllocSetStats(MemoryContext context)
|
||||
{
|
||||
AllocSet set = (AllocSet) context;
|
||||
long nblocks = 0;
|
||||
long nchunks = 0;
|
||||
long totalspace = 0;
|
||||
|
@ -557,8 +700,6 @@ AllocSetStats(AllocSet set, const char *ident)
|
|||
AllocChunk chunk;
|
||||
int fidx;
|
||||
|
||||
AssertArg(AllocSetIsValid(set));
|
||||
|
||||
for (block = set->blocks; block != NULL; block = block->next)
|
||||
{
|
||||
nblocks++;
|
||||
|
@ -576,6 +717,6 @@ AllocSetStats(AllocSet set, const char *ident)
|
|||
}
|
||||
fprintf(stderr,
|
||||
"%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n",
|
||||
ident, totalspace, nblocks, freespace, nchunks,
|
||||
set->header.name, totalspace, nblocks, freespace, nchunks,
|
||||
totalspace - freespace);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* mcxt.c
|
||||
* POSTGRES memory context code.
|
||||
* POSTGRES memory context management code.
|
||||
*
|
||||
* This module handles context management operations that are independent
|
||||
* of the particular kind of context being operated on. It calls
|
||||
* context-type-specific operations via the function pointers in a
|
||||
* context's MemoryContextMethods struct.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.21 2000/05/21 02:23:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.22 2000/06/28 03:32:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -17,323 +23,440 @@
|
|||
|
||||
#include "nodes/memnodes.h"
|
||||
#include "utils/excid.h"
|
||||
#include "utils/module.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
|
||||
|
||||
#undef MemoryContextAlloc
|
||||
#undef MemoryContextFree
|
||||
#undef malloc
|
||||
#undef free
|
||||
|
||||
/*
|
||||
* Global State
|
||||
*/
|
||||
static int MemoryContextEnableCount = 0;
|
||||
|
||||
#define MemoryContextEnabled (MemoryContextEnableCount > 0)
|
||||
|
||||
static OrderedSetData ActiveGlobalMemorySetData; /* uninitialized */
|
||||
|
||||
#define ActiveGlobalMemorySet (&ActiveGlobalMemorySetData)
|
||||
|
||||
/*
|
||||
* description of allocated memory representation goes here
|
||||
*/
|
||||
|
||||
#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
|
||||
#define PSIZEALL(PTR) (*((int32 *)(PTR) - 1) + sizeof (int32))
|
||||
#define PSIZESKIP(PTR) ((char *)((int32 *)(PTR) + 1))
|
||||
#define PSIZEFIND(PTR) ((char *)((int32 *)(PTR) - 1))
|
||||
#define PSIZESPACE(LEN) ((LEN) + sizeof (int32))
|
||||
|
||||
/*
|
||||
* AllocSizeIsValid
|
||||
* True iff 0 < size and size <= MaxAllocSize.
|
||||
*/
|
||||
#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
|
||||
|
||||
/*****************************************************************************
|
||||
* GLOBAL MEMORY *
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* CurrentMemoryContext
|
||||
* Memory context for general global allocations.
|
||||
* Default memory context for allocations.
|
||||
*/
|
||||
DLLIMPORT MemoryContext CurrentMemoryContext = NULL;
|
||||
|
||||
/*
|
||||
* Standard top-level contexts
|
||||
*/
|
||||
MemoryContext TopMemoryContext = NULL;
|
||||
MemoryContext ErrorContext = NULL;
|
||||
MemoryContext PostmasterContext = NULL;
|
||||
MemoryContext CacheMemoryContext = NULL;
|
||||
MemoryContext QueryContext = NULL;
|
||||
MemoryContext TopTransactionContext = NULL;
|
||||
MemoryContext TransactionCommandContext = NULL;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* PRIVATE DEFINITIONS *
|
||||
* EXPORTED ROUTINES *
|
||||
*****************************************************************************/
|
||||
|
||||
static Pointer GlobalMemoryAlloc(GlobalMemory this, Size size);
|
||||
static void GlobalMemoryFree(GlobalMemory this, Pointer pointer);
|
||||
static Pointer GlobalMemoryRealloc(GlobalMemory this, Pointer pointer,
|
||||
Size size);
|
||||
static char *GlobalMemoryGetName(GlobalMemory this);
|
||||
static void GlobalMemoryDump(GlobalMemory this);
|
||||
|
||||
#ifdef NOT_USED
|
||||
static void DumpGlobalMemories(void);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Global Memory Methods
|
||||
*/
|
||||
|
||||
static struct MemoryContextMethodsData GlobalContextMethodsData = {
|
||||
GlobalMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
|
||||
GlobalMemoryFree, /* void (*)(this, Pointer) pfree */
|
||||
GlobalMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
|
||||
GlobalMemoryGetName, /* char* (*)(this) getName */
|
||||
GlobalMemoryDump /* void (*)(this) dump */
|
||||
};
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* TopGlobalMemory is handled specially because of bootstrapping.
|
||||
*/
|
||||
/* extern bool EqualGlobalMemory(); */
|
||||
|
||||
static struct GlobalMemoryData TopGlobalMemoryData = {
|
||||
T_GlobalMemory, /* NodeTag tag */
|
||||
&GlobalContextMethodsData, /* ContextMethods method */
|
||||
{NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
|
||||
/* free AllocSet */
|
||||
"TopGlobal", /* char* name */
|
||||
{0} /* uninitialized OrderedElemData elemD */
|
||||
};
|
||||
|
||||
/*
|
||||
* TopMemoryContext
|
||||
* Memory context for general global allocations.
|
||||
* MemoryContextInit
|
||||
* Start up the memory-context subsystem.
|
||||
*
|
||||
* Note:
|
||||
* Don't use this memory context for random allocations. If you
|
||||
* allocate something here, you are expected to clean it up when
|
||||
* appropriate.
|
||||
*/
|
||||
MemoryContext TopMemoryContext = (MemoryContext) &TopGlobalMemoryData;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Module State
|
||||
*/
|
||||
|
||||
/*
|
||||
* EnableMemoryContext
|
||||
* Enables/disables memory management and global contexts.
|
||||
* This must be called before creating contexts or allocating memory in
|
||||
* contexts. TopMemoryContext and ErrorContext are initialized here;
|
||||
* other contexts must be created afterwards.
|
||||
*
|
||||
* Note:
|
||||
* This must be called before creating contexts or allocating memory.
|
||||
* This must be called before other contexts are created.
|
||||
* In normal multi-backend operation, this is called once during
|
||||
* postmaster startup, and not at all by individual backend startup
|
||||
* (since the backends inherit an already-initialized context subsystem
|
||||
* by virtue of being forked off the postmaster).
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if on is invalid.
|
||||
* BadState if on is false when disabled.
|
||||
* In a standalone backend this must be called during backend startup.
|
||||
*/
|
||||
void
|
||||
EnableMemoryContext(bool on)
|
||||
MemoryContextInit(void)
|
||||
{
|
||||
static bool processing = false;
|
||||
AssertState(TopMemoryContext == NULL);
|
||||
/*
|
||||
* Initialize TopMemoryContext as an AllocSetContext with slow
|
||||
* growth rate --- we don't really expect much to be allocated in it.
|
||||
*
|
||||
* (There is special-case code in MemoryContextCreate() for this call.)
|
||||
*/
|
||||
TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
|
||||
"TopMemoryContext",
|
||||
8 * 1024,
|
||||
8 * 1024,
|
||||
8 * 1024);
|
||||
/*
|
||||
* Not having any other place to point CurrentMemoryContext,
|
||||
* make it point to TopMemoryContext. Caller should change this soon!
|
||||
*/
|
||||
CurrentMemoryContext = TopMemoryContext;
|
||||
/*
|
||||
* Initialize ErrorContext as an AllocSetContext with slow
|
||||
* growth rate --- we don't really expect much to be allocated in it.
|
||||
* More to the point, require it to contain at least 8K at all times.
|
||||
* This is the only case where retained memory in a context is
|
||||
* *essential* --- we want to be sure ErrorContext still has some
|
||||
* memory even if we've run out elsewhere!
|
||||
*/
|
||||
ErrorContext = AllocSetContextCreate(TopMemoryContext,
|
||||
"ErrorContext",
|
||||
8 * 1024,
|
||||
8 * 1024,
|
||||
8 * 1024);
|
||||
}
|
||||
|
||||
AssertState(!processing);
|
||||
AssertArg(BoolIsValid(on));
|
||||
/*
|
||||
* MemoryContextReset
|
||||
* Release all space allocated within a context and its descendants,
|
||||
* but don't delete the contexts themselves.
|
||||
*
|
||||
* The type-specific reset routine handles the context itself, but we
|
||||
* have to do the recursion for the children.
|
||||
*/
|
||||
void
|
||||
MemoryContextReset(MemoryContext context)
|
||||
{
|
||||
MemoryContextResetChildren(context);
|
||||
(*context->methods->reset) (context);
|
||||
}
|
||||
|
||||
if (BypassEnable(&MemoryContextEnableCount, on))
|
||||
return;
|
||||
/*
|
||||
* MemoryContextResetChildren
|
||||
* Release all space allocated within a context's descendants,
|
||||
* but don't delete the contexts themselves. The named context
|
||||
* itself is not touched.
|
||||
*/
|
||||
void
|
||||
MemoryContextResetChildren(MemoryContext context)
|
||||
{
|
||||
MemoryContext child;
|
||||
|
||||
processing = true;
|
||||
for (child = context->firstchild; child != NULL; child = child->nextchild)
|
||||
{
|
||||
MemoryContextReset(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (on)
|
||||
{ /* initialize */
|
||||
/* initialize TopGlobalMemoryData.setData */
|
||||
AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
|
||||
(Size) 0);
|
||||
/*
|
||||
* MemoryContextDelete
|
||||
* Delete a context and its descendants, and release all space
|
||||
* allocated therein.
|
||||
*
|
||||
* The type-specific delete routine removes all subsidiary storage
|
||||
* for the context, but we have to delete the context node itself,
|
||||
* as well as recurse to get the children. We must also delink the
|
||||
* node from its parent, if it has one.
|
||||
*/
|
||||
void
|
||||
MemoryContextDelete(MemoryContext context)
|
||||
{
|
||||
/* We had better not be deleting TopMemoryContext ... */
|
||||
Assert(context != TopMemoryContext);
|
||||
/* And not CurrentMemoryContext, either */
|
||||
Assert(context != CurrentMemoryContext);
|
||||
|
||||
/* make TopGlobalMemoryData member of ActiveGlobalMemorySet */
|
||||
OrderedSetInit(ActiveGlobalMemorySet,
|
||||
offsetof(struct GlobalMemoryData, elemData));
|
||||
OrderedElemPushInto(&TopGlobalMemoryData.elemData,
|
||||
ActiveGlobalMemorySet);
|
||||
MemoryContextDeleteChildren(context);
|
||||
/*
|
||||
* We delink the context from its parent before deleting it,
|
||||
* so that if there's an error we won't have deleted/busted
|
||||
* contexts still attached to the context tree. Better a leak
|
||||
* than a crash.
|
||||
*/
|
||||
if (context->parent)
|
||||
{
|
||||
MemoryContext parent = context->parent;
|
||||
|
||||
/* initialize CurrentMemoryContext */
|
||||
CurrentMemoryContext = TopMemoryContext;
|
||||
if (context == parent->firstchild)
|
||||
{
|
||||
parent->firstchild = context->nextchild;
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryContext child;
|
||||
|
||||
for (child = parent->firstchild; child; child = child->nextchild)
|
||||
{
|
||||
if (context == child->nextchild)
|
||||
{
|
||||
child->nextchild = context->nextchild;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(*context->methods->delete) (context);
|
||||
pfree(context);
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextDeleteChildren
|
||||
* Delete all the descendants of the named context and release all
|
||||
* space allocated therein. The named context itself is not touched.
|
||||
*/
|
||||
void
|
||||
MemoryContextDeleteChildren(MemoryContext context)
|
||||
{
|
||||
/*
|
||||
* MemoryContextDelete will delink the child from me,
|
||||
* so just iterate as long as there is a child.
|
||||
*/
|
||||
while (context->firstchild != NULL)
|
||||
{
|
||||
MemoryContextDelete(context->firstchild);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextResetAndDeleteChildren
|
||||
* Release all space allocated within a context and delete all
|
||||
* its descendants.
|
||||
*
|
||||
* This is a common combination case where we want to preserve the
|
||||
* specific context but get rid of absolutely everything under it.
|
||||
*/
|
||||
void
|
||||
MemoryContextResetAndDeleteChildren(MemoryContext context)
|
||||
{
|
||||
MemoryContextDeleteChildren(context);
|
||||
(*context->methods->reset) (context);
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextStats
|
||||
* Print statistics about the named context and all its descendants.
|
||||
*
|
||||
* This is just a debugging utility, so it's not fancy. The statistics
|
||||
* are merely sent to stderr.
|
||||
*/
|
||||
void
|
||||
MemoryContextStats(MemoryContext context)
|
||||
{
|
||||
MemoryContext child;
|
||||
|
||||
(*context->methods->stats) (context);
|
||||
for (child = context->firstchild; child != NULL; child = child->nextchild)
|
||||
{
|
||||
MemoryContextStats(child);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextContains
|
||||
* Detect whether an allocated chunk of memory belongs to a given
|
||||
* context or not.
|
||||
*
|
||||
* Caution: this test is reliable as long as 'pointer' does point to
|
||||
* a chunk of memory allocated from *some* context. If 'pointer' points
|
||||
* at memory obtained in some other way, there is a small chance of a
|
||||
* false-positive result, since the bits right before it might look like
|
||||
* a valid chunk header by chance.
|
||||
*/
|
||||
bool
|
||||
MemoryContextContains(MemoryContext context, void *pointer)
|
||||
{
|
||||
StandardChunkHeader *header;
|
||||
|
||||
/*
|
||||
* Try to detect bogus pointers handed to us, poorly though we can.
|
||||
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at
|
||||
* an allocated chunk.
|
||||
*/
|
||||
if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
|
||||
return false;
|
||||
/*
|
||||
* OK, it's probably safe to look at the chunk header.
|
||||
*/
|
||||
header = (StandardChunkHeader *)
|
||||
((char *) pointer - STANDARDCHUNKHEADERSIZE);
|
||||
/*
|
||||
* If the context link doesn't match then we certainly have a
|
||||
* non-member chunk. Also check for a reasonable-looking size
|
||||
* as extra guard against being fooled by bogus pointers.
|
||||
*/
|
||||
if (header->context == context && AllocSizeIsValid(header->size))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------
|
||||
* MemoryContextCreate
|
||||
* Context-type-independent part of context creation.
|
||||
*
|
||||
* This is only intended to be called by context-type-specific
|
||||
* context creation routines, not by the unwashed masses.
|
||||
*
|
||||
* The context creation procedure is a little bit tricky because
|
||||
* we want to be sure that we don't leave the context tree invalid
|
||||
* in case of failure (such as insufficient memory to allocate the
|
||||
* context node itself). The procedure goes like this:
|
||||
* 1. Context-type-specific routine first calls MemoryContextCreate(),
|
||||
* passing the appropriate tag/size/methods values (the methods
|
||||
* pointer will ordinarily point to statically allocated data).
|
||||
* The parent and name parameters usually come from the caller.
|
||||
* 2. MemoryContextCreate() attempts to allocate the context node,
|
||||
* plus space for the name. If this fails we can elog() with no
|
||||
* damage done.
|
||||
* 3. We fill in all of the type-independent MemoryContext fields.
|
||||
* 4. We call the type-specific init routine (using the methods pointer).
|
||||
* The init routine is required to make the node minimally valid
|
||||
* with zero chance of failure --- it can't allocate more memory,
|
||||
* for example.
|
||||
* 5. Now we have a minimally valid node that can behave correctly
|
||||
* when told to reset or delete itself. We link the node to its
|
||||
* parent (if any), making the node part of the context tree.
|
||||
* 6. We return to the context-type-specific routine, which finishes
|
||||
* up type-specific initialization. This routine can now do things
|
||||
* that might fail (like allocate more memory), so long as it's
|
||||
* sure the node is left in a state that delete will handle.
|
||||
*
|
||||
* This protocol doesn't prevent us from leaking memory if step 6 fails
|
||||
* during creation of a top-level context, since there's no parent link
|
||||
* in that case. However, if you run out of memory while you're building
|
||||
* a top-level context, you might as well go home anyway...
|
||||
*
|
||||
* Normally, the context node and the name are allocated from
|
||||
* TopMemoryContext (NOT from the parent context, since the node must
|
||||
* survive resets of its parent context!). However, this routine is itself
|
||||
* used to create TopMemoryContext! If we see that TopMemoryContext is NULL,
|
||||
* we assume we are creating TopMemoryContext and use malloc() to allocate
|
||||
* the node.
|
||||
*
|
||||
* Note that the name field of a MemoryContext does not point to
|
||||
* separately-allocated storage, so it should not be freed at context
|
||||
* deletion.
|
||||
*--------------------
|
||||
*/
|
||||
MemoryContext
|
||||
MemoryContextCreate(NodeTag tag, Size size,
|
||||
MemoryContextMethods *methods,
|
||||
MemoryContext parent,
|
||||
const char *name)
|
||||
{
|
||||
MemoryContext node;
|
||||
Size needed = size + strlen(name) + 1;
|
||||
|
||||
/* Get space for node and name */
|
||||
if (TopMemoryContext != NULL)
|
||||
{
|
||||
/* Normal case: allocate the node in TopMemoryContext */
|
||||
node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
|
||||
needed);
|
||||
}
|
||||
else
|
||||
{ /* cleanup */
|
||||
GlobalMemory context;
|
||||
|
||||
/* walk the list of allocations */
|
||||
while (PointerIsValid(context = (GlobalMemory)
|
||||
OrderedSetGetHead(ActiveGlobalMemorySet)))
|
||||
{
|
||||
|
||||
if (context == &TopGlobalMemoryData)
|
||||
{
|
||||
/* don't free it and clean it last */
|
||||
OrderedElemPop(&TopGlobalMemoryData.elemData);
|
||||
}
|
||||
else
|
||||
GlobalMemoryDestroy(context);
|
||||
/* what is needed for the top? */
|
||||
}
|
||||
|
||||
/*
|
||||
* Freeing memory here should be safe as this is called only after
|
||||
* all modules which allocate in TopMemoryContext have been
|
||||
* disabled.
|
||||
*/
|
||||
|
||||
/* step through remaining allocations and log */
|
||||
/* AllocSetStep(...); */
|
||||
|
||||
/* deallocate whatever is left */
|
||||
AllocSetReset(&TopGlobalMemoryData.setData);
|
||||
{
|
||||
/* Special case for startup: use good ol' malloc */
|
||||
node = (MemoryContext) malloc(needed);
|
||||
Assert(node != NULL);
|
||||
}
|
||||
|
||||
processing = false;
|
||||
/* Initialize the node as best we can */
|
||||
MemSet(node, 0, size);
|
||||
node->type = tag;
|
||||
node->methods = methods;
|
||||
node->parent = NULL; /* for the moment */
|
||||
node->firstchild = NULL;
|
||||
node->nextchild = NULL;
|
||||
node->name = ((char *) node) + size;
|
||||
strcpy(node->name, name);
|
||||
|
||||
/* Type-specific routine finishes any other essential initialization */
|
||||
(*node->methods->init) (node);
|
||||
|
||||
/* OK to link node to parent (if any) */
|
||||
if (parent)
|
||||
{
|
||||
node->parent = parent;
|
||||
node->nextchild = parent->firstchild;
|
||||
parent->firstchild = node;
|
||||
}
|
||||
|
||||
/* Return to type-specific creation routine to finish up */
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextAlloc
|
||||
* Returns pointer to aligned allocated memory in the given context.
|
||||
* Allocate space within the specified context.
|
||||
*
|
||||
* Note:
|
||||
* none
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called before InitMemoryManager.
|
||||
* BadArg if context is invalid or if size is 0.
|
||||
* BadAllocSize if size is larger than MaxAllocSize.
|
||||
* This could be turned into a macro, but we'd have to import
|
||||
* nodes/memnodes.h into postgres.h which seems a bad idea.
|
||||
*/
|
||||
Pointer
|
||||
void *
|
||||
MemoryContextAlloc(MemoryContext context, Size size)
|
||||
{
|
||||
AssertState(MemoryContextEnabled);
|
||||
AssertArg(MemoryContextIsValid(context));
|
||||
|
||||
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
|
||||
("size=%d [0x%x]", size, size));
|
||||
|
||||
return context->method->alloc(context, size);
|
||||
return (*context->methods->alloc) (context, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextFree
|
||||
* Frees allocated memory referenced by pointer in the given context.
|
||||
*
|
||||
* Note:
|
||||
* none
|
||||
*
|
||||
* Exceptions:
|
||||
* ???
|
||||
* BadArgumentsErr if firstTime is true for subsequent calls.
|
||||
* pfree
|
||||
* Release an allocated chunk.
|
||||
*/
|
||||
void
|
||||
MemoryContextFree(MemoryContext context, Pointer pointer)
|
||||
pfree(void *pointer)
|
||||
{
|
||||
AssertState(MemoryContextEnabled);
|
||||
AssertArg(MemoryContextIsValid(context));
|
||||
AssertArg(PointerIsValid(pointer));
|
||||
StandardChunkHeader *header;
|
||||
|
||||
context->method->free_p(context, pointer);
|
||||
/*
|
||||
* Try to detect bogus pointers handed to us, poorly though we can.
|
||||
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at
|
||||
* an allocated chunk.
|
||||
*/
|
||||
Assert(pointer != NULL);
|
||||
Assert(pointer == (void *) MAXALIGN(pointer));
|
||||
/*
|
||||
* OK, it's probably safe to look at the chunk header.
|
||||
*/
|
||||
header = (StandardChunkHeader *)
|
||||
((char *) pointer - STANDARDCHUNKHEADERSIZE);
|
||||
|
||||
AssertArg(MemoryContextIsValid(header->context));
|
||||
|
||||
(*header->context->methods->free_p) (header->context, pointer);
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextRelloc
|
||||
* Returns pointer to aligned allocated memory in the given context.
|
||||
* repalloc
|
||||
*
|
||||
* Note:
|
||||
* none
|
||||
*
|
||||
* Exceptions:
|
||||
* ???
|
||||
* BadArgumentsErr if firstTime is true for subsequent calls.
|
||||
*/
|
||||
Pointer
|
||||
MemoryContextRealloc(MemoryContext context,
|
||||
Pointer pointer,
|
||||
Size size)
|
||||
void *
|
||||
repalloc(void *pointer, Size size)
|
||||
{
|
||||
AssertState(MemoryContextEnabled);
|
||||
AssertArg(MemoryContextIsValid(context));
|
||||
AssertArg(PointerIsValid(pointer));
|
||||
StandardChunkHeader *header;
|
||||
|
||||
/*
|
||||
* Try to detect bogus pointers handed to us, poorly though we can.
|
||||
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at
|
||||
* an allocated chunk.
|
||||
*/
|
||||
Assert(pointer != NULL);
|
||||
Assert(pointer == (void *) MAXALIGN(pointer));
|
||||
/*
|
||||
* OK, it's probably safe to look at the chunk header.
|
||||
*/
|
||||
header = (StandardChunkHeader *)
|
||||
((char *) pointer - STANDARDCHUNKHEADERSIZE);
|
||||
|
||||
AssertArg(MemoryContextIsValid(header->context));
|
||||
|
||||
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
|
||||
("size=%d [0x%x]", size, size));
|
||||
|
||||
return context->method->realloc(context, pointer, size);
|
||||
return (*header->context->methods->realloc) (header->context,
|
||||
pointer, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* MemoryContextGetName
|
||||
* Returns pointer to aligned allocated memory in the given context.
|
||||
*
|
||||
* Note:
|
||||
* none
|
||||
*
|
||||
* Exceptions:
|
||||
* ???
|
||||
* BadArgumentsErr if firstTime is true for subsequent calls.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
char *
|
||||
MemoryContextGetName(MemoryContext context)
|
||||
{
|
||||
AssertState(MemoryContextEnabled);
|
||||
AssertArg(MemoryContextIsValid(context));
|
||||
|
||||
return context->method->getName(context);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PointerGetAllocSize
|
||||
* Returns size of aligned allocated memory given pointer to it.
|
||||
*
|
||||
* Note:
|
||||
* none
|
||||
*
|
||||
* Exceptions:
|
||||
* ???
|
||||
* BadArgumentsErr if firstTime is true for subsequent calls.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
Size
|
||||
PointerGetAllocSize(Pointer pointer)
|
||||
{
|
||||
AssertState(MemoryContextEnabled);
|
||||
AssertArg(PointerIsValid(pointer));
|
||||
|
||||
return PSIZE(pointer);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MemoryContextSwitchTo
|
||||
* Returns the current context; installs the given context.
|
||||
*
|
||||
* Note:
|
||||
* none
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if context is invalid.
|
||||
*/
|
||||
MemoryContext
|
||||
MemoryContextSwitchTo(MemoryContext context)
|
||||
{
|
||||
MemoryContext old;
|
||||
|
||||
AssertState(MemoryContextEnabled);
|
||||
AssertArg(MemoryContextIsValid(context));
|
||||
|
||||
old = CurrentMemoryContext;
|
||||
|
@ -342,195 +465,18 @@ MemoryContextSwitchTo(MemoryContext context)
|
|||
}
|
||||
|
||||
/*
|
||||
* External Functions
|
||||
* MemoryContextStrdup
|
||||
* Like strdup(), but allocate from the specified context
|
||||
*/
|
||||
/*
|
||||
* CreateGlobalMemory
|
||||
* Returns new global memory context.
|
||||
*
|
||||
* Note:
|
||||
* Assumes name is static.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadState if called outside TopMemoryContext (TopGlobalMemory).
|
||||
* BadArg if name is invalid.
|
||||
*/
|
||||
GlobalMemory
|
||||
CreateGlobalMemory(char *name) /* XXX MemoryContextName */
|
||||
char *
|
||||
MemoryContextStrdup(MemoryContext context, const char *string)
|
||||
{
|
||||
GlobalMemory context;
|
||||
MemoryContext savecxt;
|
||||
char *nstr;
|
||||
Size len = strlen(string) + 1;
|
||||
|
||||
AssertState(MemoryContextEnabled);
|
||||
nstr = (char *) MemoryContextAlloc(context, len);
|
||||
|
||||
savecxt = MemoryContextSwitchTo(TopMemoryContext);
|
||||
memcpy(nstr, string, len);
|
||||
|
||||
context = (GlobalMemory) newNode(sizeof(struct GlobalMemoryData), T_GlobalMemory);
|
||||
context->method = &GlobalContextMethodsData;
|
||||
context->name = name; /* assumes name is static */
|
||||
AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0);
|
||||
|
||||
/* link the context */
|
||||
OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet);
|
||||
|
||||
MemoryContextSwitchTo(savecxt);
|
||||
return context;
|
||||
}
|
||||
|
||||
/*
|
||||
* GlobalMemoryDestroy
|
||||
* Destroys given global memory context.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadState if called outside TopMemoryContext (TopGlobalMemory).
|
||||
* BadArg if context is invalid GlobalMemory.
|
||||
* BadArg if context is TopMemoryContext (TopGlobalMemory).
|
||||
*/
|
||||
void
|
||||
GlobalMemoryDestroy(GlobalMemory context)
|
||||
{
|
||||
AssertState(MemoryContextEnabled);
|
||||
AssertArg(IsA(context, GlobalMemory));
|
||||
AssertArg(context != &TopGlobalMemoryData);
|
||||
|
||||
AllocSetReset(&context->setData);
|
||||
|
||||
/* unlink and delete the context */
|
||||
OrderedElemPop(&context->elemData);
|
||||
MemoryContextFree(TopMemoryContext, (Pointer) context);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* PRIVATE *
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* GlobalMemoryAlloc
|
||||
* Returns pointer to aligned space in the global context.
|
||||
*
|
||||
* Exceptions:
|
||||
* ExhaustedMemory if allocation fails.
|
||||
*/
|
||||
static Pointer
|
||||
GlobalMemoryAlloc(GlobalMemory this, Size size)
|
||||
{
|
||||
return AllocSetAlloc(&this->setData, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* GlobalMemoryFree
|
||||
* Frees allocated memory in the global context.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadContextErr if current context is not the global context.
|
||||
* BadArgumentsErr if pointer is invalid.
|
||||
*/
|
||||
static void
|
||||
GlobalMemoryFree(GlobalMemory this,
|
||||
Pointer pointer)
|
||||
{
|
||||
AllocSetFree(&this->setData, pointer);
|
||||
}
|
||||
|
||||
/*
|
||||
* GlobalMemoryRealloc
|
||||
* Returns pointer to aligned space in the global context.
|
||||
*
|
||||
* Note:
|
||||
* Memory associated with the pointer is freed before return.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadContextErr if current context is not the global context.
|
||||
* BadArgumentsErr if pointer is invalid.
|
||||
* NoMoreMemoryErr if allocation fails.
|
||||
*/
|
||||
static Pointer
|
||||
GlobalMemoryRealloc(GlobalMemory this,
|
||||
Pointer pointer,
|
||||
Size size)
|
||||
{
|
||||
return AllocSetRealloc(&this->setData, pointer, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* GlobalMemoryGetName
|
||||
* Returns name string for context.
|
||||
*
|
||||
* Exceptions:
|
||||
* ???
|
||||
*/
|
||||
static char *
|
||||
GlobalMemoryGetName(GlobalMemory this)
|
||||
{
|
||||
return this->name;
|
||||
}
|
||||
|
||||
/*
|
||||
* GlobalMemoryDump
|
||||
* Dumps global memory context for debugging.
|
||||
*
|
||||
* Exceptions:
|
||||
* ???
|
||||
*/
|
||||
static void
|
||||
GlobalMemoryDump(GlobalMemory this)
|
||||
{
|
||||
GlobalMemory context;
|
||||
|
||||
printf("--\n%s:\n", GlobalMemoryGetName(this));
|
||||
|
||||
context = (GlobalMemory) OrderedElemGetPredecessor(&this->elemData);
|
||||
if (PointerIsValid(context))
|
||||
printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
|
||||
|
||||
context = (GlobalMemory) OrderedElemGetSuccessor(&this->elemData);
|
||||
if (PointerIsValid(context))
|
||||
printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
|
||||
|
||||
AllocSetDump(&this->setData);
|
||||
}
|
||||
|
||||
/*
|
||||
* DumpGlobalMemories
|
||||
* Dumps all global memory contexts for debugging.
|
||||
*
|
||||
* Exceptions:
|
||||
* ???
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
static void
|
||||
DumpGlobalMemories()
|
||||
{
|
||||
GlobalMemory context;
|
||||
|
||||
context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
|
||||
|
||||
while (PointerIsValid(context))
|
||||
{
|
||||
GlobalMemoryDump(context);
|
||||
|
||||
context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GlobalMemoryStats
|
||||
* Displays stats about memory consumption of all global contexts.
|
||||
*/
|
||||
void
|
||||
GlobalMemoryStats(void)
|
||||
{
|
||||
GlobalMemory context;
|
||||
|
||||
context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
|
||||
|
||||
while (PointerIsValid(context))
|
||||
{
|
||||
AllocSetStats(&context->setData, GlobalMemoryGetName(context));
|
||||
context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
|
||||
}
|
||||
return nstr;
|
||||
}
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* oset.c
|
||||
* Fixed format ordered set definitions.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/oset.c,v 1.17 2000/04/12 17:16:10 momjian Exp $
|
||||
*
|
||||
* NOTE
|
||||
* XXX This is a preliminary implementation which lacks fail-fast
|
||||
* XXX validity checking of arguments.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "utils/memutils.h"
|
||||
|
||||
static Pointer OrderedElemGetBase(OrderedElem elem);
|
||||
static void OrderedElemPush(OrderedElem elem);
|
||||
static void OrderedElemPushHead(OrderedElem elem);
|
||||
|
||||
/*
|
||||
* OrderedElemGetBase
|
||||
* Returns base of enclosing structure.
|
||||
*/
|
||||
static Pointer
|
||||
OrderedElemGetBase(OrderedElem elem)
|
||||
{
|
||||
if (elem == (OrderedElem) NULL)
|
||||
return (Pointer) NULL;
|
||||
|
||||
return (Pointer) ((char *) (elem) - (elem)->set->offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedSetInit
|
||||
*/
|
||||
void
|
||||
OrderedSetInit(OrderedSet set, Offset offset)
|
||||
{
|
||||
set->head = (OrderedElem) &set->dummy;
|
||||
set->dummy = NULL;
|
||||
set->tail = (OrderedElem) &set->head;
|
||||
set->offset = offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedSetContains
|
||||
* True iff ordered set contains given element.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
bool
|
||||
OrderedSetContains(OrderedSet set, OrderedElem elem)
|
||||
{
|
||||
return (bool) (elem->set == set && (elem->next || elem->prev));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OrderedSetGetHead
|
||||
*/
|
||||
Pointer
|
||||
OrderedSetGetHead(OrderedSet set)
|
||||
{
|
||||
OrderedElem elem;
|
||||
|
||||
elem = set->head;
|
||||
if (elem->next)
|
||||
return OrderedElemGetBase(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedSetGetTail
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
Pointer
|
||||
OrderedSetGetTail(OrderedSet set)
|
||||
{
|
||||
OrderedElem elem;
|
||||
|
||||
elem = set->tail;
|
||||
if (elem->prev)
|
||||
return OrderedElemGetBase(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OrderedElemGetPredecessor
|
||||
*/
|
||||
Pointer
|
||||
OrderedElemGetPredecessor(OrderedElem elem)
|
||||
{
|
||||
elem = elem->prev;
|
||||
if (elem->prev)
|
||||
return OrderedElemGetBase(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedElemGetSuccessor
|
||||
*/
|
||||
Pointer
|
||||
OrderedElemGetSuccessor(OrderedElem elem)
|
||||
{
|
||||
elem = elem->next;
|
||||
if (elem->next)
|
||||
return OrderedElemGetBase(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedElemPop
|
||||
*/
|
||||
void
|
||||
OrderedElemPop(OrderedElem elem)
|
||||
{
|
||||
elem->next->prev = elem->prev;
|
||||
elem->prev->next = elem->next;
|
||||
/* assignments used only for error detection */
|
||||
elem->next = NULL;
|
||||
elem->prev = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedElemPushInto
|
||||
*/
|
||||
void
|
||||
OrderedElemPushInto(OrderedElem elem, OrderedSet set)
|
||||
{
|
||||
elem->set = set;
|
||||
/* mark as unattached */
|
||||
elem->next = NULL;
|
||||
elem->prev = NULL;
|
||||
OrderedElemPush(elem);
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedElemPush
|
||||
*/
|
||||
static void
|
||||
OrderedElemPush(OrderedElem elem)
|
||||
{
|
||||
OrderedElemPushHead(elem);
|
||||
}
|
||||
|
||||
/*
|
||||
* OrderedElemPushHead
|
||||
*/
|
||||
static void
|
||||
OrderedElemPushHead(OrderedElem elem)
|
||||
{
|
||||
elem->next = elem->set->head;
|
||||
elem->prev = (OrderedElem) &elem->set->head;
|
||||
elem->next->prev = elem;
|
||||
elem->prev->next = elem;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* palloc.c
|
||||
* POSTGRES memory allocator code.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.18 2000/05/30 00:49:57 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* User library functions
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------
|
||||
* palloc(), pfree() and repalloc() are now macros in palloc.h
|
||||
* ----------
|
||||
*/
|
||||
|
||||
char *
|
||||
pstrdup(const char *string)
|
||||
{
|
||||
char *nstr;
|
||||
int len;
|
||||
|
||||
nstr = palloc(len = strlen(string) + 1);
|
||||
memcpy(nstr, string, len);
|
||||
|
||||
return nstr;
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.36 2000/04/12 17:16:10 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.37 2000/06/28 03:32:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -40,67 +40,28 @@
|
|||
*
|
||||
* struct PortalD {
|
||||
* char* name;
|
||||
* classObj(PortalVariableMemory) variable;
|
||||
* classObj(PortalHeapMemory) heap;
|
||||
* classObj(MemoryContext) heap;
|
||||
* List queryDesc;
|
||||
* EState state;
|
||||
* void (*cleanup) ARGS((Portal portal));
|
||||
* };
|
||||
*
|
||||
* I hope this makes things clearer to whoever reads this -cim 2/22/91
|
||||
*
|
||||
* Here is an old comment taken from nodes/memnodes.h
|
||||
*
|
||||
* MemoryContext
|
||||
* A logical context in which memory allocations occur.
|
||||
*
|
||||
* The types of memory contexts can be thought of as members of the
|
||||
* following inheritance hierarchy with properties summarized below.
|
||||
*
|
||||
* Node
|
||||
* |
|
||||
* MemoryContext___
|
||||
* / \
|
||||
* GlobalMemory PortalMemoryContext
|
||||
* / \
|
||||
* PortalVariableMemory PortalHeapMemory
|
||||
*
|
||||
* Flushed at Flushed at Checkpoints
|
||||
* Transaction Portal
|
||||
* Commit Close
|
||||
*
|
||||
* GlobalMemory n n n
|
||||
* PortalVariableMemory n y n
|
||||
* PortalHeapMemory y y y *
|
||||
*
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "lib/hasht.h"
|
||||
#include "utils/module.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/portal.h"
|
||||
|
||||
static void CollectNamedPortals(Portal *portalP, int destroy);
|
||||
static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
|
||||
static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
|
||||
static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
|
||||
|
||||
/* ----------------
|
||||
* ALLOCFREE_ERROR_ABORT
|
||||
* define this if you want a core dump when you try to
|
||||
* free memory already freed -cim 2/9/91
|
||||
* ----------------
|
||||
*/
|
||||
#undef ALLOCFREE_ERROR_ABORT
|
||||
|
||||
/* ----------------
|
||||
* Global state
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
static int PortalManagerEnableCount = 0;
|
||||
|
||||
#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
|
||||
|
||||
typedef struct portalhashent
|
||||
|
@ -109,8 +70,6 @@ typedef struct portalhashent
|
|||
Portal portal;
|
||||
} PortalHashEnt;
|
||||
|
||||
#define PortalManagerEnabled (PortalManagerEnableCount >= 1)
|
||||
|
||||
static HTAB *PortalHashTable = NULL;
|
||||
|
||||
#define PortalHashTableLookup(NAME, PORTAL) \
|
||||
|
@ -158,263 +117,13 @@ do { \
|
|||
elog(NOTICE, "trying to delete portal name that does not exist."); \
|
||||
} while(0)
|
||||
|
||||
static GlobalMemory PortalMemory = NULL;
|
||||
static char PortalMemoryName[] = "Portal";
|
||||
|
||||
static Portal BlankPortal = NULL;
|
||||
|
||||
/* ----------------
|
||||
* Internal class definitions
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct HeapMemoryBlockData
|
||||
{
|
||||
AllocSetData setData;
|
||||
FixedItemData itemData;
|
||||
} HeapMemoryBlockData;
|
||||
|
||||
typedef HeapMemoryBlockData *HeapMemoryBlock;
|
||||
|
||||
#define HEAPMEMBLOCK(context) \
|
||||
((HeapMemoryBlock)(context)->block)
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Variable and heap memory methods
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
/* ----------------
|
||||
* PortalVariableMemoryAlloc
|
||||
* ----------------
|
||||
*/
|
||||
static Pointer
|
||||
PortalVariableMemoryAlloc(PortalVariableMemory this,
|
||||
Size size)
|
||||
{
|
||||
return AllocSetAlloc(&this->setData, size);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalVariableMemoryFree
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
PortalVariableMemoryFree(PortalVariableMemory this,
|
||||
Pointer pointer)
|
||||
{
|
||||
AllocSetFree(&this->setData, pointer);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalVariableMemoryRealloc
|
||||
* ----------------
|
||||
*/
|
||||
static Pointer
|
||||
PortalVariableMemoryRealloc(PortalVariableMemory this,
|
||||
Pointer pointer,
|
||||
Size size)
|
||||
{
|
||||
return AllocSetRealloc(&this->setData, pointer, size);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalVariableMemoryGetName
|
||||
* ----------------
|
||||
*/
|
||||
static char *
|
||||
PortalVariableMemoryGetName(PortalVariableMemory this)
|
||||
{
|
||||
return vararg_format("%s-var", PortalVariableMemoryGetPortal(this)->name);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalVariableMemoryDump
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
PortalVariableMemoryDump(PortalVariableMemory this)
|
||||
{
|
||||
printf("--\n%s:\n", PortalVariableMemoryGetName(this));
|
||||
|
||||
AllocSetDump(&this->setData); /* XXX is this the right interface */
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalHeapMemoryAlloc
|
||||
* ----------------
|
||||
*/
|
||||
static Pointer
|
||||
PortalHeapMemoryAlloc(PortalHeapMemory this,
|
||||
Size size)
|
||||
{
|
||||
HeapMemoryBlock block = HEAPMEMBLOCK(this);
|
||||
|
||||
AssertState(PointerIsValid(block));
|
||||
|
||||
return AllocSetAlloc(&block->setData, size);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalHeapMemoryFree
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
PortalHeapMemoryFree(PortalHeapMemory this,
|
||||
Pointer pointer)
|
||||
{
|
||||
HeapMemoryBlock block = HEAPMEMBLOCK(this);
|
||||
|
||||
AssertState(PointerIsValid(block));
|
||||
|
||||
if (AllocSetContains(&block->setData, pointer))
|
||||
AllocSetFree(&block->setData, pointer);
|
||||
else
|
||||
{
|
||||
elog(NOTICE,
|
||||
"PortalHeapMemoryFree: 0x%p not in alloc set!",
|
||||
pointer);
|
||||
#ifdef ALLOCFREE_ERROR_ABORT
|
||||
Assert(AllocSetContains(&block->setData, pointer));
|
||||
#endif /* ALLOCFREE_ERROR_ABORT */
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalHeapMemoryRealloc
|
||||
* ----------------
|
||||
*/
|
||||
static Pointer
|
||||
PortalHeapMemoryRealloc(PortalHeapMemory this,
|
||||
Pointer pointer,
|
||||
Size size)
|
||||
{
|
||||
HeapMemoryBlock block = HEAPMEMBLOCK(this);
|
||||
|
||||
AssertState(PointerIsValid(block));
|
||||
|
||||
return AllocSetRealloc(&block->setData, pointer, size);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalHeapMemoryGetName
|
||||
* ----------------
|
||||
*/
|
||||
static char *
|
||||
PortalHeapMemoryGetName(PortalHeapMemory this)
|
||||
{
|
||||
return vararg_format("%s-heap", PortalHeapMemoryGetPortal(this)->name);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalHeapMemoryDump
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
PortalHeapMemoryDump(PortalHeapMemory this)
|
||||
{
|
||||
HeapMemoryBlock block;
|
||||
|
||||
printf("--\n%s:\n", PortalHeapMemoryGetName(this));
|
||||
|
||||
/* XXX is this the right interface */
|
||||
if (PointerIsValid(this->block))
|
||||
AllocSetDump(&HEAPMEMBLOCK(this)->setData);
|
||||
|
||||
/* dump the stack too */
|
||||
for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
|
||||
PointerIsValid(block);
|
||||
block = (HeapMemoryBlock)
|
||||
FixedStackGetNext(&this->stackData, (Pointer) block))
|
||||
{
|
||||
|
||||
printf("--\n");
|
||||
AllocSetDump(&block->setData);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* variable / heap context method tables
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
|
||||
PortalVariableMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
|
||||
PortalVariableMemoryFree, /* void (*)(this, Pointer) pfree */
|
||||
PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer) repalloc */
|
||||
PortalVariableMemoryGetName,/* char* (*)(this) getName */
|
||||
PortalVariableMemoryDump /* void (*)(this) dump */
|
||||
};
|
||||
|
||||
static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
|
||||
PortalHeapMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
|
||||
PortalHeapMemoryFree, /* void (*)(this, Pointer) pfree */
|
||||
PortalHeapMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
|
||||
PortalHeapMemoryGetName, /* char* (*)(this) getName */
|
||||
PortalHeapMemoryDump /* void (*)(this) dump */
|
||||
};
|
||||
static MemoryContext PortalMemory = NULL;
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* private internal support routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
/* ----------------
|
||||
* CreateNewBlankPortal
|
||||
* ----------------
|
||||
*/
|
||||
static void
|
||||
CreateNewBlankPortal()
|
||||
{
|
||||
Portal portal;
|
||||
|
||||
AssertState(!PortalIsValid(BlankPortal));
|
||||
|
||||
/*
|
||||
* make new portal structure
|
||||
*/
|
||||
portal = (Portal)
|
||||
MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
|
||||
|
||||
/*
|
||||
* initialize portal variable context
|
||||
*/
|
||||
NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
|
||||
AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
|
||||
portal->variable.method = &PortalVariableContextMethodsData;
|
||||
|
||||
/*
|
||||
* initialize portal heap context
|
||||
*/
|
||||
NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
|
||||
portal->heap.block = NULL;
|
||||
FixedStackInit(&portal->heap.stackData,
|
||||
offsetof(HeapMemoryBlockData, itemData));
|
||||
portal->heap.method = &PortalHeapContextMethodsData;
|
||||
|
||||
/*
|
||||
* set bogus portal name
|
||||
*/
|
||||
portal->name = "** Blank Portal **";
|
||||
|
||||
/* initialize portal query */
|
||||
portal->queryDesc = NULL;
|
||||
portal->attinfo = NULL;
|
||||
portal->state = NULL;
|
||||
portal->cleanup = NULL;
|
||||
|
||||
/*
|
||||
* install blank portal
|
||||
*/
|
||||
BlankPortal = portal;
|
||||
}
|
||||
|
||||
bool
|
||||
PortalNameIsSpecial(char *pname)
|
||||
{
|
||||
if (strcmp(pname, VACPNAME) == 0)
|
||||
return true;
|
||||
if (strcmp(pname, TRUNCPNAME) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is used to collect all portals created in this xaction
|
||||
|
@ -447,12 +156,6 @@ CollectNamedPortals(Portal *portalP, int destroy)
|
|||
Assert(portalP);
|
||||
Assert(*portalP);
|
||||
|
||||
/*
|
||||
* Don't delete special portals, up to portal creator to do this
|
||||
*/
|
||||
if (PortalNameIsSpecial((*portalP)->name))
|
||||
return;
|
||||
|
||||
portalList[listIndex] = *portalP;
|
||||
listIndex++;
|
||||
if (listIndex == maxIndex)
|
||||
|
@ -472,179 +175,50 @@ AtEOXact_portals()
|
|||
CollectNamedPortals(NULL, 1);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalDump
|
||||
* ----------------
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
static void
|
||||
PortalDump(Portal *thisP, int dummy)
|
||||
{
|
||||
/* XXX state/argument checking here */
|
||||
|
||||
PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
|
||||
PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
* DumpPortals
|
||||
* ----------------
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
static void
|
||||
DumpPortals()
|
||||
{
|
||||
/* XXX state checking here */
|
||||
|
||||
HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* public portal interface functions
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* EnablePortalManager
|
||||
* Enables/disables the portal management module.
|
||||
* Enables the portal management module at backend startup.
|
||||
*/
|
||||
void
|
||||
EnablePortalManager(bool on)
|
||||
EnablePortalManager(void)
|
||||
{
|
||||
static bool processing = false;
|
||||
HASHCTL ctl;
|
||||
|
||||
AssertState(!processing);
|
||||
AssertArg(BoolIsValid(on));
|
||||
Assert(PortalMemory == NULL);
|
||||
|
||||
if (BypassEnable(&PortalManagerEnableCount, on))
|
||||
return;
|
||||
PortalMemory = AllocSetContextCreate(TopMemoryContext,
|
||||
"PortalMemory",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
processing = true;
|
||||
ctl.keysize = MAX_PORTALNAME_LEN;
|
||||
ctl.datasize = sizeof(Portal);
|
||||
|
||||
if (on)
|
||||
{ /* initialize */
|
||||
EnableMemoryContext(true);
|
||||
|
||||
PortalMemory = CreateGlobalMemory(PortalMemoryName);
|
||||
|
||||
ctl.keysize = MAX_PORTALNAME_LEN;
|
||||
ctl.datasize = sizeof(Portal);
|
||||
|
||||
/*
|
||||
* use PORTALS_PER_USER, defined in utils/portal.h as a guess of
|
||||
* how many hash table entries to create, initially
|
||||
*/
|
||||
PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
|
||||
|
||||
CreateNewBlankPortal();
|
||||
|
||||
}
|
||||
else
|
||||
{ /* cleanup */
|
||||
if (PortalIsValid(BlankPortal))
|
||||
{
|
||||
PortalDrop(&BlankPortal);
|
||||
MemoryContextFree((MemoryContext) PortalMemory,
|
||||
(Pointer) BlankPortal);
|
||||
BlankPortal = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each portal must free its non-memory resources specially.
|
||||
*/
|
||||
HashTableWalk(PortalHashTable, (HashtFunc) PortalDrop, 0);
|
||||
hash_destroy(PortalHashTable);
|
||||
PortalHashTable = NULL;
|
||||
|
||||
GlobalMemoryDestroy(PortalMemory);
|
||||
PortalMemory = NULL;
|
||||
|
||||
EnableMemoryContext(true);
|
||||
}
|
||||
|
||||
processing = false;
|
||||
/*
|
||||
* use PORTALS_PER_USER, defined in utils/portal.h as a guess of
|
||||
* how many hash table entries to create, initially
|
||||
*/
|
||||
PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* GetPortalByName
|
||||
* Returns a portal given a portal name; returns blank portal given
|
||||
* NULL; returns invalid portal if portal not found.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* Returns a portal given a portal name, or NULL if name not found.
|
||||
*/
|
||||
Portal
|
||||
GetPortalByName(char *name)
|
||||
{
|
||||
Portal portal;
|
||||
|
||||
AssertState(PortalManagerEnabled);
|
||||
|
||||
if (PointerIsValid(name))
|
||||
PortalHashTableLookup(name, portal);
|
||||
else
|
||||
{
|
||||
if (!PortalIsValid(BlankPortal))
|
||||
CreateNewBlankPortal();
|
||||
portal = BlankPortal;
|
||||
}
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
||||
/*
|
||||
* BlankPortalAssignName
|
||||
* Returns former blank portal as portal with given name.
|
||||
*
|
||||
* Side effect:
|
||||
* All references to the former blank portal become incorrect.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadState if called without an intervening call to GetPortalByName(NULL).
|
||||
* BadArg if portal name is invalid.
|
||||
* "WARN" if portal name is in use.
|
||||
*/
|
||||
Portal
|
||||
BlankPortalAssignName(char *name) /* XXX PortalName */
|
||||
{
|
||||
Portal portal;
|
||||
uint16 length;
|
||||
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertState(PortalIsValid(BlankPortal));
|
||||
AssertArg(PointerIsValid(name)); /* XXX PortalName */
|
||||
|
||||
portal = GetPortalByName(name);
|
||||
if (PortalIsValid(portal))
|
||||
{
|
||||
elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
|
||||
return portal;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove blank portal
|
||||
*/
|
||||
portal = BlankPortal;
|
||||
BlankPortal = NULL;
|
||||
|
||||
/*
|
||||
* initialize portal name
|
||||
*/
|
||||
length = 1 + strlen(name);
|
||||
portal->name = (char *)
|
||||
MemoryContextAlloc((MemoryContext) &portal->variable, length);
|
||||
|
||||
strncpy(portal->name, name, length);
|
||||
|
||||
/*
|
||||
* put portal in table
|
||||
*/
|
||||
PortalHashTableInsert(portal);
|
||||
portal = NULL;
|
||||
|
||||
return portal;
|
||||
}
|
||||
|
@ -666,7 +240,6 @@ PortalSetQuery(Portal portal,
|
|||
EState *state,
|
||||
void (*cleanup) (Portal portal))
|
||||
{
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertArg(PortalIsValid(portal));
|
||||
AssertArg(IsA((Node *) state, EState));
|
||||
|
||||
|
@ -687,7 +260,6 @@ PortalSetQuery(Portal portal,
|
|||
QueryDesc *
|
||||
PortalGetQueryDesc(Portal portal)
|
||||
{
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertArg(PortalIsValid(portal));
|
||||
|
||||
return portal->queryDesc;
|
||||
|
@ -704,7 +276,6 @@ PortalGetQueryDesc(Portal portal)
|
|||
EState *
|
||||
PortalGetState(Portal portal)
|
||||
{
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertArg(PortalIsValid(portal));
|
||||
|
||||
return portal->state;
|
||||
|
@ -714,63 +285,48 @@ PortalGetState(Portal portal)
|
|||
* CreatePortal
|
||||
* Returns a new portal given a name.
|
||||
*
|
||||
* Note:
|
||||
* This is expected to be of very limited usability. See instead,
|
||||
* BlankPortalAssignName.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if portal name is invalid.
|
||||
* "WARN" if portal name is in use.
|
||||
* "NOTICE" if portal name is in use (existing portal is returned!)
|
||||
*/
|
||||
Portal
|
||||
CreatePortal(char *name) /* XXX PortalName */
|
||||
CreatePortal(char *name)
|
||||
{
|
||||
Portal portal;
|
||||
uint16 length;
|
||||
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertArg(PointerIsValid(name)); /* XXX PortalName */
|
||||
AssertArg(PointerIsValid(name));
|
||||
|
||||
portal = GetPortalByName(name);
|
||||
if (PortalIsValid(portal))
|
||||
{
|
||||
elog(NOTICE, "CreatePortal: portal %s already exists", name);
|
||||
elog(NOTICE, "CreatePortal: portal \"%s\" already exists", name);
|
||||
return portal;
|
||||
}
|
||||
|
||||
/* make new portal structure */
|
||||
portal = (Portal)
|
||||
MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
|
||||
|
||||
/* initialize portal variable context */
|
||||
NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
|
||||
AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
|
||||
portal->variable.method = &PortalVariableContextMethodsData;
|
||||
|
||||
/* initialize portal heap context */
|
||||
NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
|
||||
portal->heap.block = NULL;
|
||||
FixedStackInit(&portal->heap.stackData,
|
||||
offsetof(HeapMemoryBlockData, itemData));
|
||||
portal->heap.method = &PortalHeapContextMethodsData;
|
||||
portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
|
||||
|
||||
/* initialize portal name */
|
||||
length = 1 + strlen(name);
|
||||
portal->name = (char *)
|
||||
MemoryContextAlloc((MemoryContext) &portal->variable, length);
|
||||
strncpy(portal->name, name, length);
|
||||
portal->name = MemoryContextStrdup(PortalMemory, name);
|
||||
|
||||
/* initialize portal heap context */
|
||||
portal->heap = AllocSetContextCreate(PortalMemory,
|
||||
"PortalHeapMemory",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
|
||||
/* initialize portal query */
|
||||
portal->queryDesc = NULL;
|
||||
portal->attinfo = NULL;
|
||||
portal->state = NULL;
|
||||
|
||||
portal->cleanup = NULL;
|
||||
|
||||
/* put portal in table */
|
||||
PortalHashTableInsert(portal);
|
||||
|
||||
/* Trap(PointerIsValid(name), Unimplemented); */
|
||||
return portal;
|
||||
}
|
||||
|
||||
|
@ -787,240 +343,29 @@ PortalDrop(Portal *portalP)
|
|||
{
|
||||
Portal portal = *portalP;
|
||||
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertArg(PortalIsValid(portal));
|
||||
|
||||
/* remove portal from table if not blank portal */
|
||||
if (portal != BlankPortal)
|
||||
PortalHashTableDelete(portal);
|
||||
/* remove portal from hash table */
|
||||
PortalHashTableDelete(portal);
|
||||
|
||||
/* reset portal */
|
||||
if (PointerIsValid(portal->cleanup))
|
||||
(*portal->cleanup) (portal);
|
||||
|
||||
PortalResetHeapMemory(portal);
|
||||
MemoryContextFree((MemoryContext) &portal->variable,
|
||||
(Pointer) portal->name);
|
||||
AllocSetReset(&portal->variable.setData); /* XXX log */
|
||||
/* release subsidiary storage */
|
||||
MemoryContextDelete(PortalGetHeapMemory(portal));
|
||||
|
||||
/*
|
||||
* In the case of a transaction abort it is possible that we get
|
||||
* called while one of the memory contexts of the portal we're
|
||||
* destroying is the current memory context.
|
||||
*
|
||||
* Don't know how to handle that cleanly because it is required to be in
|
||||
* that context right now. This portal struct remains allocated in the
|
||||
* PortalMemory context until backend dies.
|
||||
*
|
||||
* Not happy with that, but it's better to loose some bytes of memory
|
||||
* than to have the backend dump core.
|
||||
*
|
||||
* --- Feb. 04, 1999 Jan Wieck
|
||||
*/
|
||||
if (CurrentMemoryContext == (MemoryContext) PortalGetHeapMemory(portal))
|
||||
return;
|
||||
if (CurrentMemoryContext == (MemoryContext) PortalGetVariableMemory(portal))
|
||||
return;
|
||||
|
||||
if (portal != BlankPortal)
|
||||
MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* PortalResetHeapMemory
|
||||
* Resets portal's heap memory context.
|
||||
*
|
||||
* Someday, Reset, Start, and End can be optimized by keeping a global
|
||||
* portal module stack of free HeapMemoryBlock's. This will make Start
|
||||
* and End be fast.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadState if called when not in PortalHeapMemory context.
|
||||
* BadArg if mode is invalid.
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
PortalResetHeapMemory(Portal portal)
|
||||
{
|
||||
PortalHeapMemory context;
|
||||
MemoryContext currentContext;
|
||||
|
||||
context = PortalGetHeapMemory(portal);
|
||||
|
||||
if (PointerIsValid(context->block))
|
||||
{
|
||||
/* save present context */
|
||||
currentContext = MemoryContextSwitchTo((MemoryContext) context);
|
||||
|
||||
do
|
||||
{
|
||||
EndPortalAllocMode();
|
||||
} while (PointerIsValid(context->block));
|
||||
|
||||
/* restore context */
|
||||
MemoryContextSwitchTo(currentContext);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* StartPortalAllocMode
|
||||
* Starts a new block of portal heap allocation using mode and limit;
|
||||
* the current block is disabled until EndPortalAllocMode is called.
|
||||
*
|
||||
* Note:
|
||||
* Note blocks may be stacked and restored arbitarily.
|
||||
* The semantics of mode and limit are described in aset.h.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadState if called when not in PortalHeapMemory context.
|
||||
* BadArg if mode is invalid.
|
||||
*/
|
||||
void
|
||||
StartPortalAllocMode(AllocMode mode, Size limit)
|
||||
{
|
||||
PortalHeapMemory context;
|
||||
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
|
||||
/* AssertArg(AllocModeIsValid); */
|
||||
|
||||
context = (PortalHeapMemory) CurrentMemoryContext;
|
||||
|
||||
/* stack current mode */
|
||||
if (PointerIsValid(context->block))
|
||||
FixedStackPush(&context->stackData, context->block);
|
||||
|
||||
/* allocate and initialize new block */
|
||||
context->block = MemoryContextAlloc(
|
||||
(MemoryContext) PortalHeapMemoryGetVariableMemory(context),
|
||||
sizeof(HeapMemoryBlockData));
|
||||
|
||||
/* XXX careful, context->block has never been stacked => bad state */
|
||||
|
||||
AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
|
||||
}
|
||||
|
||||
/*
|
||||
* EndPortalAllocMode
|
||||
* Ends current block of portal heap allocation; previous block is
|
||||
* reenabled.
|
||||
*
|
||||
* Note:
|
||||
* Note blocks may be stacked and restored arbitarily.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadState if called when not in PortalHeapMemory context.
|
||||
*/
|
||||
void
|
||||
EndPortalAllocMode()
|
||||
{
|
||||
PortalHeapMemory context;
|
||||
|
||||
AssertState(PortalManagerEnabled);
|
||||
AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
|
||||
|
||||
context = (PortalHeapMemory) CurrentMemoryContext;
|
||||
AssertState(PointerIsValid(context->block)); /* XXX Trap(...) */
|
||||
|
||||
/* free current mode */
|
||||
AllocSetReset(&HEAPMEMBLOCK(context)->setData);
|
||||
MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
|
||||
context->block);
|
||||
|
||||
/* restore previous mode */
|
||||
context->block = FixedStackPop(&context->stackData);
|
||||
}
|
||||
|
||||
/*
|
||||
* PortalGetVariableMemory
|
||||
* Returns variable memory context for a given portal.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if portal is invalid.
|
||||
*/
|
||||
PortalVariableMemory
|
||||
PortalGetVariableMemory(Portal portal)
|
||||
{
|
||||
return &portal->variable;
|
||||
/* release name and portal data (both are in PortalMemory) */
|
||||
pfree(portal->name);
|
||||
pfree(portal);
|
||||
}
|
||||
|
||||
/*
|
||||
* PortalGetHeapMemory
|
||||
* Returns heap memory context for a given portal.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if portal is invalid.
|
||||
*/
|
||||
PortalHeapMemory
|
||||
MemoryContext
|
||||
PortalGetHeapMemory(Portal portal)
|
||||
{
|
||||
return &portal->heap;
|
||||
}
|
||||
|
||||
/*
|
||||
* PortalVariableMemoryGetPortal
|
||||
* Returns portal containing given variable memory context.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if context is invalid.
|
||||
*/
|
||||
static Portal
|
||||
PortalVariableMemoryGetPortal(PortalVariableMemory context)
|
||||
{
|
||||
return (Portal) ((char *) context - offsetof(PortalD, variable));
|
||||
}
|
||||
|
||||
/*
|
||||
* PortalHeapMemoryGetPortal
|
||||
* Returns portal containing given heap memory context.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if context is invalid.
|
||||
*/
|
||||
static Portal
|
||||
PortalHeapMemoryGetPortal(PortalHeapMemory context)
|
||||
{
|
||||
return (Portal) ((char *) context - offsetof(PortalD, heap));
|
||||
}
|
||||
|
||||
/*
|
||||
* PortalVariableMemoryGetHeapMemory
|
||||
* Returns heap memory context associated with given variable memory.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if context is invalid.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
PortalHeapMemory
|
||||
PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
|
||||
{
|
||||
return ((PortalHeapMemory) ((char *) context
|
||||
- offsetof(PortalD, variable)
|
||||
+offsetof(PortalD, heap)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PortalHeapMemoryGetVariableMemory
|
||||
* Returns variable memory context associated with given heap memory.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadState if called when disabled.
|
||||
* BadArg if context is invalid.
|
||||
*/
|
||||
static PortalVariableMemory
|
||||
PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
|
||||
{
|
||||
return ((PortalVariableMemory) ((char *) context
|
||||
- offsetof(PortalD, heap)
|
||||
+offsetof(PortalD, variable)));
|
||||
return portal->heap;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: command.h,v 1.18 2000/04/12 17:16:31 momjian Exp $
|
||||
* $Id: command.h,v 1.19 2000/06/28 03:32:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include "utils/portal.h"
|
||||
|
||||
extern MemoryContext PortalExecutorHeapMemory;
|
||||
|
||||
/*
|
||||
* PerformPortalFetch
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: hashjoin.h,v 1.16 2000/01/26 05:58:05 momjian Exp $
|
||||
* $Id: hashjoin.h,v 1.17 2000/06/28 03:33:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -22,20 +22,19 @@
|
|||
*
|
||||
* Each active hashjoin has a HashJoinTable control block which is
|
||||
* palloc'd in the executor's context. All other storage needed for
|
||||
* the hashjoin is kept in a private "named portal", one for each hashjoin.
|
||||
* the hashjoin is kept in private memory contexts, two for each hashjoin.
|
||||
* This makes it easy and fast to release the storage when we don't need it
|
||||
* anymore.
|
||||
*
|
||||
* The portal manager guarantees that portals will be discarded at end of
|
||||
* transaction, so we have no problem with a memory leak if the join is
|
||||
* The contexts are made children of TransactionCommandContext, ensuring
|
||||
* that they will be discarded at end of statement even if the join is
|
||||
* aborted early by an error. (Likewise, any temporary files we make will
|
||||
* be cleaned up by the virtual file manager in event of an error.)
|
||||
*
|
||||
* Storage that should live through the entire join is allocated from the
|
||||
* portal's "variable context", while storage that is only wanted for the
|
||||
* current batch is allocated in the portal's "heap context". By popping
|
||||
* the portal's heap at the end of a batch, we free all the per-batch storage
|
||||
* reliably and without tedium.
|
||||
* "hashCxt", while storage that is only wanted for the current batch is
|
||||
* allocated in the "batchCxt". By resetting the batchCxt at the end of
|
||||
* each batch, we free all the per-batch storage reliably and without tedium.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -80,15 +79,6 @@ typedef struct HashTableData
|
|||
* to hash buckets and output.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Ugly kluge: myPortal ought to be declared as type Portal (ie,
|
||||
* PortalD*) but if we try to include utils/portal.h here, we end up
|
||||
* with a circular dependency of include files! Until the various
|
||||
* node.h files are restructured in a cleaner way, we have to fake it.
|
||||
* The most reliable fake seems to be to declare myPortal as void *
|
||||
* and then cast it to the right things in nodeHash.c.
|
||||
*/
|
||||
void *myPortal; /* where to keep working storage */
|
||||
MemoryContext hashCxt; /* context for whole-hash-join storage */
|
||||
MemoryContext batchCxt; /* context for this-batch-only storage */
|
||||
} HashTableData;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "utils/fcache.h"
|
||||
#include "utils/datum.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/portal.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "access/heapam.h"
|
||||
|
@ -95,4 +94,6 @@ extern void *SPI_repalloc(void *pointer, Size size);
|
|||
extern void SPI_pfree(void *pointer);
|
||||
extern void SPI_freetuple(HeapTuple pointer);
|
||||
|
||||
extern void AtEOXact_SPI(void);
|
||||
|
||||
#endif /* SPI_H */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* spi.c
|
||||
* Server Programming Interface private declarations
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.6 1999/07/15 15:21:14 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.7 2000/06/28 03:33:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -17,7 +17,8 @@ typedef struct
|
|||
List *qtlist;
|
||||
uint32 processed; /* by Executor */
|
||||
SPITupleTable *tuptable;
|
||||
Portal portal; /* portal per procedure */
|
||||
MemoryContext procCxt; /* procedure context */
|
||||
MemoryContext execCxt; /* executor context */
|
||||
MemoryContext savedcxt;
|
||||
CommandId savedId;
|
||||
} _SPI_connection;
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* fstack.h
|
||||
* Fixed format stack definitions.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: fstack.h,v 1.9 2000/01/26 05:58:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* Note:
|
||||
* Fixed format stacks assist in the construction of FIFO stacks of
|
||||
* fixed format structures. Structures which are to be stackable
|
||||
* should contain a FixedItemData component. A stack is initilized
|
||||
* with the offset of the FixedItemData component of the structure
|
||||
* it will hold. By doing so, push and pop operations are simplified
|
||||
* for the callers. All references to stackable items are pointers
|
||||
* to the base of the structure instead of pointers to the
|
||||
* FixedItemData component.
|
||||
*
|
||||
*/
|
||||
#ifndef FSTACK_H
|
||||
#define FSTACK_H
|
||||
|
||||
|
||||
/*
|
||||
* FixedItem
|
||||
* Fixed format stackable item chain component.
|
||||
*
|
||||
* Note:
|
||||
* Structures must contain one FixedItemData component per stack in
|
||||
* which it will be an item.
|
||||
*/
|
||||
typedef struct FixedItemData FixedItemData;
|
||||
typedef FixedItemData *FixedItem;
|
||||
|
||||
struct FixedItemData
|
||||
{
|
||||
FixedItem next; /* next item or NULL */
|
||||
};
|
||||
|
||||
/*
|
||||
* FixedStack
|
||||
* Fixed format stack.
|
||||
*/
|
||||
typedef struct FixedStackData
|
||||
{
|
||||
FixedItem top; /* Top item on the stack or NULL */
|
||||
Offset offset; /* Offset from struct base to item */
|
||||
/* this could be signed short int! */
|
||||
} FixedStackData;
|
||||
|
||||
typedef FixedStackData *FixedStack;
|
||||
|
||||
/*
|
||||
* FixedStackInit
|
||||
* Iniitializes stack for structures with given fixed component offset.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if stack is invalid pointer.
|
||||
*/
|
||||
extern void FixedStackInit(FixedStack stack, Offset offset);
|
||||
|
||||
/*
|
||||
* FixedStackPop
|
||||
* Returns pointer to top structure on stack or NULL if empty stack.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if stack is invalid.
|
||||
*/
|
||||
Pointer FixedStackPop(FixedStack stack);
|
||||
|
||||
/*
|
||||
* FixedStackPush
|
||||
* Places structure associated with pointer onto top of stack.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if stack is invalid.
|
||||
* BadArg if pointer is invalid.
|
||||
*/
|
||||
extern void FixedStackPush(FixedStack stack, Pointer pointer);
|
||||
|
||||
/*
|
||||
* FixedStackGetTop
|
||||
* Returns pointer to top structure of a stack. This item is not poped.
|
||||
*
|
||||
* Note:
|
||||
* This is not part of the normal stack interface. It is intended for
|
||||
* debugging use only.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if stack is invalid.
|
||||
*/
|
||||
extern Pointer FixedStackGetTop(FixedStack stack);
|
||||
|
||||
/*
|
||||
* FixedStackGetNext
|
||||
* Returns pointer to next structure after pointer of a stack.
|
||||
*
|
||||
* Note:
|
||||
* This is not part of the normal stack interface. It is intended for
|
||||
* debugging use only.
|
||||
*
|
||||
* Exceptions:
|
||||
* BadArg if stack is invalid.
|
||||
* BadArg if pointer is invalid.
|
||||
* BadArg if stack does not contain pointer.
|
||||
*/
|
||||
extern Pointer FixedStackGetNext(FixedStack stack, Pointer pointer);
|
||||
|
||||
#endif /* FSTACK_H */
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqsignal.h,v 1.13 2000/06/15 00:52:11 momjian Exp $
|
||||
* $Id: pqsignal.h,v 1.14 2000/06/28 03:33:14 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This shouldn't be in libpq, but the monitor and some other
|
||||
|
@ -24,28 +24,18 @@
|
|||
extern sigset_t UnBlockSig,
|
||||
BlockSig;
|
||||
|
||||
#define PG_INITMASK() ( \
|
||||
sigemptyset(&UnBlockSig), \
|
||||
sigfillset(&BlockSig) \
|
||||
)
|
||||
#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)
|
||||
#else
|
||||
extern int UnBlockSig,
|
||||
BlockSig;
|
||||
|
||||
#define PG_INITMASK() ( \
|
||||
UnBlockSig = 0, \
|
||||
BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) | \
|
||||
sigmask(SIGTERM) | sigmask(SIGALRM) | \
|
||||
sigmask(SIGINT) | sigmask(SIGUSR1) | \
|
||||
sigmask(SIGUSR2) | sigmask(SIGCHLD) | \
|
||||
sigmask(SIGWINCH) | sigmask(SIGFPE) \
|
||||
)
|
||||
#define PG_SETMASK(mask) sigsetmask(*((int*)(mask)))
|
||||
#endif
|
||||
|
||||
typedef void (*pqsigfunc) (int);
|
||||
|
||||
extern void pqinitmask(void);
|
||||
|
||||
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
|
||||
|
||||
#endif /* PQSIGNAL_H */
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: miscadmin.h,v 1.60 2000/06/15 00:52:04 momjian Exp $
|
||||
* $Id: miscadmin.h,v 1.61 2000/06/28 03:32:56 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* some of the information in this file will be moved to
|
||||
|
@ -105,8 +105,6 @@ extern bool enableFsync;
|
|||
extern bool allowSystemTableMods;
|
||||
extern int SortMem;
|
||||
|
||||
extern Oid LastOidProcessed; /* for query rewrite */
|
||||
|
||||
/* a few postmaster startup options are exported here so the
|
||||
configuration file processor has access to them */
|
||||
|
||||
|
@ -189,9 +187,10 @@ typedef int16 ExitStatus;
|
|||
|
||||
/* in utils/init/postinit.c */
|
||||
|
||||
extern bool PostgresIsInitialized;
|
||||
extern int lockingOff;
|
||||
|
||||
extern void InitPostgres(const char *dbname);
|
||||
extern void BaseInit(void);
|
||||
|
||||
/* one of the ways to get out of here */
|
||||
#define ExitPostgres(status) proc_exec(status)
|
||||
|
|
|
@ -7,100 +7,88 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: memnodes.h,v 1.16 2000/01/26 05:58:16 momjian Exp $
|
||||
* $Id: memnodes.h,v 1.17 2000/06/28 03:33:15 tgl Exp $
|
||||
*
|
||||
* XXX the typedefs in this file are different from the other ???nodes.h;
|
||||
* they are pointers to structures instead of the structures themselves.
|
||||
* If you're wondering, this is plain laziness. I don't want to touch
|
||||
* the memory context code which should be revamped altogether some day.
|
||||
* - ay 10/94
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MEMNODES_H
|
||||
#define MEMNODES_H
|
||||
|
||||
#include "lib/fstack.h"
|
||||
#include "nodes/nodes.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
/*
|
||||
* MemoryContext
|
||||
* A logical context in which memory allocations occur.
|
||||
*
|
||||
* The types of memory contexts can be thought of as members of the
|
||||
* following inheritance hierarchy with properties summarized below.
|
||||
* MemoryContext itself is an abstract type that can have multiple
|
||||
* implementations, though for now we have only AllocSetContext.
|
||||
* The function pointers in MemoryContextMethods define one specific
|
||||
* implementation of MemoryContext --- they are a virtual function table
|
||||
* in C++ terms.
|
||||
*
|
||||
* Node
|
||||
* |
|
||||
* MemoryContext___
|
||||
* / \
|
||||
* GlobalMemory PortalMemoryContext
|
||||
* / \
|
||||
* PortalVariableMemory PortalHeapMemory
|
||||
* Node types that are actual implementations of memory contexts must
|
||||
* begin with the same fields as MemoryContext.
|
||||
*
|
||||
* Flushed at Flushed at Checkpoints
|
||||
* Transaction Portal
|
||||
* Commit Close
|
||||
*
|
||||
* GlobalMemory n n n
|
||||
* PortalVariableMemory n y n
|
||||
* PortalHeapMemory y y y
|
||||
* Note: for largely historical reasons, typedef MemoryContext is a pointer
|
||||
* to the context struct rather than the struct type itself.
|
||||
*/
|
||||
|
||||
typedef struct MemoryContextMethodsData
|
||||
typedef struct MemoryContextMethods
|
||||
{
|
||||
Pointer (*alloc) ();
|
||||
void (*free_p) (); /* need to use free as a #define, so can't
|
||||
* use free */
|
||||
Pointer (*realloc) ();
|
||||
char *(*getName) ();
|
||||
void (*dump) ();
|
||||
} *MemoryContextMethods;
|
||||
void *(*alloc) (MemoryContext context, Size size);
|
||||
/* call this free_p in case someone #define's free() */
|
||||
void (*free_p) (MemoryContext context, void *pointer);
|
||||
void *(*realloc) (MemoryContext context, void *pointer, Size size);
|
||||
void (*init) (MemoryContext context);
|
||||
void (*reset) (MemoryContext context);
|
||||
void (*delete) (MemoryContext context);
|
||||
void (*stats) (MemoryContext context);
|
||||
} MemoryContextMethods;
|
||||
|
||||
|
||||
typedef struct MemoryContextData
|
||||
{
|
||||
NodeTag type;
|
||||
MemoryContextMethods method;
|
||||
NodeTag type; /* identifies exact kind of context */
|
||||
MemoryContextMethods *methods; /* virtual function table */
|
||||
MemoryContext parent; /* NULL if no parent (toplevel context) */
|
||||
MemoryContext firstchild; /* head of linked list of children */
|
||||
MemoryContext nextchild; /* next child of same parent */
|
||||
char *name; /* context name (just for debugging) */
|
||||
} MemoryContextData;
|
||||
|
||||
/* utils/mcxt.h contains typedef struct MemoryContextData *MemoryContext */
|
||||
/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */
|
||||
|
||||
/* think about doing this right some time but we'll have explicit fields
|
||||
for now -ay 10/94 */
|
||||
typedef struct GlobalMemoryData
|
||||
|
||||
/*
|
||||
* AllocSetContext is our standard implementation of MemoryContext.
|
||||
*/
|
||||
typedef struct AllocBlockData *AllocBlock; /* internal to aset.c */
|
||||
typedef struct AllocChunkData *AllocChunk;
|
||||
|
||||
typedef struct AllocSetContext
|
||||
{
|
||||
NodeTag type;
|
||||
MemoryContextMethods method;
|
||||
AllocSetData setData;
|
||||
char *name;
|
||||
OrderedElemData elemData;
|
||||
} GlobalMemoryData;
|
||||
MemoryContextData header; /* Standard memory-context fields */
|
||||
/* Info about storage allocated in this context: */
|
||||
AllocBlock blocks; /* head of list of blocks in this set */
|
||||
#define ALLOCSET_NUM_FREELISTS 8
|
||||
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
|
||||
/* Allocation parameters for this context: */
|
||||
Size initBlockSize; /* initial block size */
|
||||
Size maxBlockSize; /* maximum block size */
|
||||
AllocBlock keeper; /* if not NULL, keep this block
|
||||
* over resets */
|
||||
} AllocSetContext;
|
||||
|
||||
/* utils/mcxt.h contains typedef struct GlobalMemoryData *GlobalMemory */
|
||||
|
||||
typedef struct MemoryContextData *PortalMemoryContext;
|
||||
|
||||
typedef struct PortalVariableMemoryData
|
||||
{
|
||||
NodeTag type;
|
||||
MemoryContextMethods method;
|
||||
AllocSetData setData;
|
||||
} *PortalVariableMemory;
|
||||
|
||||
typedef struct PortalHeapMemoryData
|
||||
{
|
||||
NodeTag type;
|
||||
MemoryContextMethods method;
|
||||
Pointer block;
|
||||
FixedStackData stackData;
|
||||
} *PortalHeapMemory;
|
||||
|
||||
/*
|
||||
* MemoryContextIsValid
|
||||
* True iff memory context is valid.
|
||||
*
|
||||
* Add new context types to the set accepted by this macro.
|
||||
*/
|
||||
#define MemoryContextIsValid(context) \
|
||||
(IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \
|
||||
IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory))
|
||||
((context) != NULL && \
|
||||
(IsA((context), AllocSetContext)))
|
||||
|
||||
|
||||
#endif /* MEMNODES_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodes.h,v 1.69 2000/06/18 22:44:31 tgl Exp $
|
||||
* $Id: nodes.h,v 1.70 2000/06/28 03:33:15 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -122,10 +122,7 @@ typedef enum NodeTag
|
|||
*---------------------
|
||||
*/
|
||||
T_MemoryContext = 400,
|
||||
T_GlobalMemory,
|
||||
T_PortalMemoryContext,
|
||||
T_PortalVariableMemory,
|
||||
T_PortalHeapMemory,
|
||||
T_AllocSetContext,
|
||||
|
||||
/*---------------------
|
||||
* TAGS FOR VALUE NODES (pg_list.h)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: geqo.h,v 1.19 2000/05/31 00:28:38 petere Exp $
|
||||
* $Id: geqo.h,v 1.20 2000/06/28 03:33:22 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -65,7 +65,6 @@ extern int Geqo_random_seed; /* or negative to use current time */
|
|||
extern RelOptInfo *geqo(Query *root);
|
||||
|
||||
/* routines in geqo_eval.c */
|
||||
extern void geqo_eval_startup(void);
|
||||
extern Cost geqo_eval(Query *root, Gene *tour, int num_gene);
|
||||
extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count,
|
||||
int num_gene, RelOptInfo *old_rel);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1995, Regents of the University of California
|
||||
*
|
||||
* $Id: postgres.h,v 1.41 2000/06/13 07:35:24 tgl Exp $
|
||||
* $Id: postgres.h,v 1.42 2000/06/28 03:32:56 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -39,7 +39,6 @@
|
|||
#include "postgres_ext.h"
|
||||
#include "c.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/mcxt.h"
|
||||
#include "utils/palloc.h"
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: shmem.h,v 1.22 2000/01/26 05:58:33 momjian Exp $
|
||||
* $Id: shmem.h,v 1.23 2000/06/28 03:33:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -63,14 +63,13 @@ typedef struct SHM_QUEUE
|
|||
extern void ShmemIndexReset(void);
|
||||
extern void ShmemCreate(unsigned int key, unsigned int size);
|
||||
extern int InitShmem(unsigned int key, unsigned int size);
|
||||
extern long *ShmemAlloc(unsigned long size);
|
||||
extern void *ShmemAlloc(Size size);
|
||||
extern int ShmemIsValid(unsigned long addr);
|
||||
extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
|
||||
HASHCTL *infoP, int hash_flags);
|
||||
extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
|
||||
extern SHMEM_OFFSET ShmemPIDDestroy(int pid);
|
||||
extern long *ShmemInitStruct(char *name, unsigned long size,
|
||||
bool *foundPtr);
|
||||
extern void *ShmemInitStruct(char *name, Size size, bool *foundPtr);
|
||||
|
||||
|
||||
typedef int TableID;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pquery.h,v 1.14 2000/01/26 05:58:35 momjian Exp $
|
||||
* $Id: pquery.h,v 1.15 2000/06/28 03:33:28 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -15,20 +15,13 @@
|
|||
#define PQUERY_H
|
||||
|
||||
#include "executor/execdesc.h"
|
||||
#include "utils/portal.h"
|
||||
|
||||
/* moved to execdesc.h
|
||||
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
||||
CommandDest dest);
|
||||
|
||||
*/
|
||||
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
|
||||
|
||||
extern EState *CreateExecutorState(void);
|
||||
|
||||
extern Portal PreparePortal(char *portalName);
|
||||
|
||||
extern void ProcessPortal(char *portalName, Query *parseTree,
|
||||
Plan *plan, EState *state, TupleDesc attinfo,
|
||||
CommandDest dest);
|
||||
|
||||
extern void
|
||||
ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
|
||||
|
||||
#endif /* pqueryIncluded */
|
||||
#endif /* PQUERY_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: tcopprot.h,v 1.30 2000/06/15 03:33:04 momjian Exp $
|
||||
* $Id: tcopprot.h,v 1.31 2000/06/28 03:33:28 tgl Exp $
|
||||
*
|
||||
* OLD COMMENTS
|
||||
* This file was created so that other c files could get the two
|
||||
|
@ -33,12 +33,11 @@ extern bool ShowPortNumber;
|
|||
#ifndef BOOTSTRAP_INCLUDE
|
||||
|
||||
extern List *pg_parse_and_rewrite(char *query_string,
|
||||
Oid *typev, int nargs,
|
||||
bool aclOverride);
|
||||
Oid *typev, int nargs);
|
||||
extern Plan *pg_plan_query(Query *querytree);
|
||||
extern void pg_exec_query_dest(char *query_string,
|
||||
CommandDest dest,
|
||||
bool aclOverride);
|
||||
CommandDest dest,
|
||||
MemoryContext parse_context);
|
||||
|
||||
#endif /* BOOTSTRAP_INCLUDE */
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catcache.h,v 1.24 2000/06/17 04:56:29 tgl Exp $
|
||||
* $Id: catcache.h,v 1.25 2000/06/28 03:33:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -75,8 +75,10 @@ typedef struct catcache
|
|||
|
||||
#define InvalidCatalogCacheId (-1)
|
||||
|
||||
extern GlobalMemory CacheCxt;
|
||||
/* this extern duplicates utils/memutils.h... */
|
||||
extern MemoryContext CacheMemoryContext;
|
||||
|
||||
extern void CreateCacheMemoryContext(void);
|
||||
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
|
||||
ItemPointer pointer);
|
||||
extern void ResetSystemCache(void);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: hsearch.h,v 1.15 2000/04/12 17:16:55 momjian Exp $
|
||||
* $Id: hsearch.h,v 1.16 2000/06/28 03:33:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -84,8 +84,7 @@ typedef struct htab
|
|||
char *segbase; /* segment base address for calculating
|
||||
* pointer values */
|
||||
SEG_OFFSET *dir; /* 'directory' of segm starts */
|
||||
long *(*alloc) (); /* memory allocator (long * for alignment
|
||||
* reasons) */
|
||||
void *(*alloc) (Size); /* memory allocator */
|
||||
} HTAB;
|
||||
|
||||
typedef struct hashctl
|
||||
|
@ -99,7 +98,7 @@ typedef struct hashctl
|
|||
long max_dsize; /* limit to dsize if directory size is
|
||||
* limited */
|
||||
long *segbase; /* base for calculating bucket + seg ptrs */
|
||||
long *(*alloc) (); /* memory allocation function */
|
||||
void *(*alloc) (Size); /* memory allocation function */
|
||||
long *dir; /* directory if allocated already */
|
||||
long *hctl; /* location of header information in shd
|
||||
* mem */
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* mcxt.h
|
||||
* POSTGRES memory context definitions.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: mcxt.h,v 1.17 2000/05/21 02:23:28 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MCXT_H
|
||||
#define MCXT_H
|
||||
|
||||
/* These types are declared in nodes/memnodes.h, but most users of memory
|
||||
* allocation should just treat them as abstract types, so we do not provide
|
||||
* the struct contents here.
|
||||
*/
|
||||
|
||||
typedef struct MemoryContextData *MemoryContext;
|
||||
typedef struct GlobalMemoryData *GlobalMemory;
|
||||
|
||||
|
||||
extern DLLIMPORT MemoryContext CurrentMemoryContext;
|
||||
extern MemoryContext TopMemoryContext;
|
||||
|
||||
|
||||
/*
|
||||
* MaxAllocSize
|
||||
* Arbitrary limit on size of allocations.
|
||||
*
|
||||
* Note:
|
||||
* There is no guarantee that allocations smaller than MaxAllocSize
|
||||
* will succeed. Allocation requests larger than MaxAllocSize will
|
||||
* be summarily denied.
|
||||
*
|
||||
* This value should not be referenced except in one place in the code.
|
||||
*
|
||||
* XXX This should be defined in a file of tunable constants.
|
||||
*/
|
||||
#define MaxAllocSize (0xfffffff) /* 16G - 1 */
|
||||
|
||||
/*
|
||||
* prototypes for functions in mcxt.c
|
||||
*/
|
||||
extern void EnableMemoryContext(bool on);
|
||||
extern Pointer MemoryContextAlloc(MemoryContext context, Size size);
|
||||
extern Pointer MemoryContextRealloc(MemoryContext context,
|
||||
Pointer pointer,
|
||||
Size size);
|
||||
extern void MemoryContextFree(MemoryContext context, Pointer pointer);
|
||||
extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
|
||||
extern GlobalMemory CreateGlobalMemory(char *name);
|
||||
extern void GlobalMemoryDestroy(GlobalMemory context);
|
||||
extern void GlobalMemoryStats(void);
|
||||
|
||||
|
||||
#endif /* MCXT_H */
|
|
@ -1,230 +1,114 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* memutils.h
|
||||
* this file contains general memory alignment, allocation
|
||||
* and manipulation stuff that used to be spread out
|
||||
* between the following files:
|
||||
*
|
||||
* align.h alignment macros
|
||||
* aset.h memory allocation set stuff
|
||||
* oset.h (used by aset.h)
|
||||
* This file contains declarations for memory allocation utility
|
||||
* functions. These are functions that are not quite widely used
|
||||
* enough to justify going in utils/palloc.h, but are still part
|
||||
* of the API of the memory management subsystem.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: memutils.h,v 1.35 2000/05/21 02:23:28 tgl Exp $
|
||||
* $Id: memutils.h,v 1.36 2000/06/28 03:33:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MEMUTILS_H
|
||||
#define MEMUTILS_H
|
||||
|
||||
/* ----------------
|
||||
* Alignment macros: align a length or address appropriately for a given type.
|
||||
*
|
||||
* There used to be some incredibly crufty platform-dependent hackery here,
|
||||
* but now we rely on the configure script to get the info for us. Much nicer.
|
||||
*
|
||||
* NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
|
||||
* That case seems extremely unlikely to occur in practice, however.
|
||||
* ----------------
|
||||
*/
|
||||
#include "nodes/memnodes.h"
|
||||
|
||||
#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
|
||||
|
||||
#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN))
|
||||
#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN))
|
||||
#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN))
|
||||
#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
|
||||
#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
|
||||
|
||||
/*****************************************************************************
|
||||
* oset.h -- Fixed format ordered set definitions. *
|
||||
*****************************************************************************/
|
||||
/* Note:
|
||||
* Fixed format ordered sets are <EXPLAIN>.
|
||||
* XXX This is a preliminary version. Work is needed to explain
|
||||
* XXX semantics of the external definitions. Otherwise, the
|
||||
* XXX functional interface should not change.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct OrderedElemData OrderedElemData;
|
||||
typedef OrderedElemData *OrderedElem;
|
||||
|
||||
typedef struct OrderedSetData OrderedSetData;
|
||||
typedef OrderedSetData *OrderedSet;
|
||||
|
||||
struct OrderedElemData
|
||||
{
|
||||
OrderedElem next; /* Next elem or &this->set->dummy */
|
||||
OrderedElem prev; /* Previous elem or &this->set->head */
|
||||
OrderedSet set; /* Parent set */
|
||||
};
|
||||
|
||||
struct OrderedSetData
|
||||
{
|
||||
OrderedElem head; /* First elem or &this->dummy */
|
||||
OrderedElem dummy; /* (hack) Terminator == NULL */
|
||||
OrderedElem tail; /* Last elem or &this->head */
|
||||
Offset offset; /* Offset from struct base to elem */
|
||||
/* this could be signed short int! */
|
||||
};
|
||||
|
||||
extern void OrderedSetInit(OrderedSet set, Offset offset);
|
||||
extern Pointer OrderedSetGetHead(OrderedSet set);
|
||||
extern Pointer OrderedElemGetPredecessor(OrderedElem elem);
|
||||
extern Pointer OrderedElemGetSuccessor(OrderedElem elem);
|
||||
extern void OrderedElemPop(OrderedElem elem);
|
||||
extern void OrderedElemPushInto(OrderedElem elem, OrderedSet Set);
|
||||
|
||||
/*****************************************************************************
|
||||
* aset.h -- Allocation set definitions. *
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* Description:
|
||||
* An allocation set is a set containing allocated elements. When
|
||||
* an allocation is requested for a set, memory is allocated and a
|
||||
* pointer is returned. Subsequently, this memory may be freed or
|
||||
* reallocated. In addition, an allocation set may be reset which
|
||||
* will cause all memory allocated within it to be freed.
|
||||
*
|
||||
* XXX The following material about allocation modes is all OUT OF DATE.
|
||||
* aset.c currently implements only one allocation strategy,
|
||||
* DynamicAllocMode, and that's the only one anyone ever requests anyway.
|
||||
* If we ever did have more strategies, the new ones might or might
|
||||
* not look like what is described here...
|
||||
*
|
||||
* Allocations may occur in four different modes. The mode of
|
||||
* allocation does not affect the behavior of allocations except in
|
||||
* terms of performance. The allocation mode is set at the time of
|
||||
* set initialization. Once the mode is chosen, it cannot be changed
|
||||
* unless the set is reinitialized.
|
||||
*
|
||||
* "Dynamic" mode forces all allocations to occur in a heap. This
|
||||
* is a good mode to use when small memory segments are allocated
|
||||
* and freed very frequently. This is a good choice when allocation
|
||||
* characteristics are unknown. This is the default mode.
|
||||
*
|
||||
* "Static" mode attempts to allocate space as efficiently as possible
|
||||
* without regard to freeing memory. This mode should be chosen only
|
||||
* when it is known that many allocations will occur but that very
|
||||
* little of the allocated memory will be explicitly freed.
|
||||
*
|
||||
* "Tunable" mode is a hybrid of dynamic and static modes. The
|
||||
* tunable mode will use static mode allocation except when the
|
||||
* allocation request exceeds a size limit supplied at the time of set
|
||||
* initialization. "Big" objects are allocated using dynamic mode.
|
||||
*
|
||||
* "Bounded" mode attempts to allocate space efficiently given a limit
|
||||
* on space consumed by the allocation set. This restriction can be
|
||||
* considered a "soft" restriction, because memory segments will
|
||||
* continue to be returned after the limit is exceeded. The limit is
|
||||
* specified at the time of set initialization like for tunable mode.
|
||||
* MaxAllocSize
|
||||
* Arbitrary limit on size of allocations.
|
||||
*
|
||||
* Note:
|
||||
* Allocation sets are not automatically reset on a system reset.
|
||||
* Higher level code is responsible for cleaning up.
|
||||
* There is no guarantee that allocations smaller than MaxAllocSize
|
||||
* will succeed. Allocation requests larger than MaxAllocSize will
|
||||
* be summarily denied.
|
||||
*
|
||||
* There may be other modes in the future.
|
||||
* XXX This should be defined in a file of tunable constants.
|
||||
*/
|
||||
#define MaxAllocSize ((Size) 0xfffffff) /* 16G - 1 */
|
||||
|
||||
#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
|
||||
|
||||
/*
|
||||
* AllocPointer
|
||||
* Aligned pointer which may be a member of an allocation set.
|
||||
* All chunks allocated by any memory context manager are required to be
|
||||
* preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
|
||||
* A currently-allocated chunk must contain a backpointer to its owning
|
||||
* context as well as the allocated size of the chunk. The backpointer is
|
||||
* used by pfree() and repalloc() to find the context to call. The allocated
|
||||
* size is not absolutely essential, but it's expected to be needed by any
|
||||
* reasonable implementation.
|
||||
*/
|
||||
typedef Pointer AllocPointer;
|
||||
typedef struct StandardChunkHeader
|
||||
{
|
||||
MemoryContext context; /* owning context */
|
||||
Size size; /* size of data space allocated in chunk */
|
||||
} StandardChunkHeader;
|
||||
|
||||
#define STANDARDCHUNKHEADERSIZE MAXALIGN(sizeof(StandardChunkHeader))
|
||||
|
||||
|
||||
/*
|
||||
* AllocMode
|
||||
* Mode of allocation for an allocation set.
|
||||
* Standard top-level memory contexts.
|
||||
*
|
||||
* Note:
|
||||
* See above for a description of the various modes.
|
||||
* Only TopMemoryContext and ErrorContext are initialized by
|
||||
* MemoryContextInit() itself.
|
||||
*/
|
||||
typedef enum AllocMode
|
||||
{
|
||||
DynamicAllocMode, /* always dynamically allocate */
|
||||
StaticAllocMode, /* always "statically" allocate */
|
||||
TunableAllocMode, /* allocations are "tuned" */
|
||||
BoundedAllocMode /* allocations bounded to fixed usage */
|
||||
} AllocMode;
|
||||
extern MemoryContext TopMemoryContext;
|
||||
extern MemoryContext ErrorContext;
|
||||
extern MemoryContext PostmasterContext;
|
||||
extern MemoryContext CacheMemoryContext;
|
||||
extern MemoryContext QueryContext;
|
||||
extern MemoryContext TopTransactionContext;
|
||||
extern MemoryContext TransactionCommandContext;
|
||||
|
||||
#define DefaultAllocMode DynamicAllocMode
|
||||
|
||||
typedef struct AllocSetData *AllocSet;
|
||||
typedef struct AllocBlockData *AllocBlock;
|
||||
typedef struct AllocChunkData *AllocChunk;
|
||||
|
||||
/*
|
||||
* AllocSet
|
||||
* Allocation set.
|
||||
* Memory-context-type-independent functions in mcxt.c
|
||||
*/
|
||||
typedef struct AllocSetData
|
||||
{
|
||||
AllocBlock blocks; /* head of list of blocks in this set */
|
||||
#define ALLOCSET_NUM_FREELISTS 8
|
||||
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
|
||||
/* Note: this will change in the future to support other modes */
|
||||
} AllocSetData;
|
||||
extern void MemoryContextInit(void);
|
||||
extern void MemoryContextReset(MemoryContext context);
|
||||
extern void MemoryContextDelete(MemoryContext context);
|
||||
extern void MemoryContextResetChildren(MemoryContext context);
|
||||
extern void MemoryContextDeleteChildren(MemoryContext context);
|
||||
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
|
||||
extern void MemoryContextStats(MemoryContext context);
|
||||
extern bool MemoryContextContains(MemoryContext context, void *pointer);
|
||||
|
||||
/*
|
||||
* AllocBlock
|
||||
* An AllocBlock is the unit of memory that is obtained by aset.c
|
||||
* from malloc(). It contains one or more AllocChunks, which are
|
||||
* the units requested by palloc() and freed by pfree(). AllocChunks
|
||||
* cannot be returned to malloc() individually, instead they are put
|
||||
* on freelists by pfree() and re-used by the next palloc() that has
|
||||
* a matching request size.
|
||||
*
|
||||
* AllocBlockData is the header data for a block --- the usable space
|
||||
* within the block begins at the next alignment boundary.
|
||||
* This routine handles the context-type-independent part of memory
|
||||
* context creation. It's intended to be called from context-type-
|
||||
* specific creation routines, and noplace else.
|
||||
*/
|
||||
typedef struct AllocBlockData
|
||||
{
|
||||
AllocSet aset; /* aset that owns this block */
|
||||
AllocBlock next; /* next block in aset's blocks list */
|
||||
char *freeptr; /* start of free space in this block */
|
||||
char *endptr; /* end of space in this block */
|
||||
} AllocBlockData;
|
||||
extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
|
||||
MemoryContextMethods *methods,
|
||||
MemoryContext parent,
|
||||
const char *name);
|
||||
|
||||
|
||||
/*
|
||||
* AllocChunk
|
||||
* The prefix of each piece of memory in an AllocBlock
|
||||
* Memory-context-type-specific functions
|
||||
*/
|
||||
typedef struct AllocChunkData
|
||||
{
|
||||
/* aset is the owning aset if allocated, or the freelist link if free */
|
||||
void *aset;
|
||||
/* size is always the size of the usable space in the chunk */
|
||||
Size size;
|
||||
} AllocChunkData;
|
||||
|
||||
/* aset.c */
|
||||
extern MemoryContext AllocSetContextCreate(MemoryContext parent,
|
||||
const char *name,
|
||||
Size minContextSize,
|
||||
Size initBlockSize,
|
||||
Size maxBlockSize);
|
||||
|
||||
/*
|
||||
* AllocPointerIsValid
|
||||
* True iff pointer is valid allocation pointer.
|
||||
* Recommended default alloc parameters, suitable for "ordinary" contexts
|
||||
* that might hold quite a lot of data.
|
||||
*/
|
||||
#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
|
||||
|
||||
/*
|
||||
* AllocSetIsValid
|
||||
* True iff set is valid allocation set.
|
||||
*/
|
||||
#define AllocSetIsValid(set) PointerIsValid(set)
|
||||
|
||||
extern void AllocSetInit(AllocSet set, AllocMode mode, Size limit);
|
||||
|
||||
extern void AllocSetReset(AllocSet set);
|
||||
|
||||
extern bool AllocSetContains(AllocSet set, AllocPointer pointer);
|
||||
extern AllocPointer AllocSetAlloc(AllocSet set, Size size);
|
||||
extern void AllocSetFree(AllocSet set, AllocPointer pointer);
|
||||
extern AllocPointer AllocSetRealloc(AllocSet set, AllocPointer pointer,
|
||||
Size size);
|
||||
|
||||
extern void AllocSetDump(AllocSet set);
|
||||
extern void AllocSetStats(AllocSet set, const char *ident);
|
||||
#define ALLOCSET_DEFAULT_MINSIZE (8 * 1024)
|
||||
#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024)
|
||||
#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024)
|
||||
|
||||
|
||||
#endif /* MEMUTILS_H */
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* module.h
|
||||
* this file contains general "module" stuff that used to be
|
||||
* spread out between the following files:
|
||||
*
|
||||
* enbl.h module enable stuff
|
||||
* trace.h module trace stuff (now gone)
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: module.h,v 1.6 2000/01/26 05:58:38 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef MODULE_H
|
||||
#define MODULE_H
|
||||
|
||||
/*
|
||||
* prototypes for functions in init/enbl.c
|
||||
*/
|
||||
extern bool BypassEnable(int *enableCountInOutP, bool on);
|
||||
|
||||
#endif /* MODULE_H */
|
|
@ -3,36 +3,85 @@
|
|||
* palloc.h
|
||||
* POSTGRES memory allocator definitions.
|
||||
*
|
||||
* This file contains the basic memory allocation interface that is
|
||||
* needed by almost every backend module. It is included directly by
|
||||
* postgres.h, so the definitions here are automatically available
|
||||
* everywhere. Keep it lean!
|
||||
*
|
||||
* Memory allocation occurs within "contexts". Every chunk obtained from
|
||||
* palloc()/MemoryContextAlloc() is allocated within a specific context.
|
||||
* The entire contents of a context can be freed easily and quickly by
|
||||
* resetting or deleting the context --- this is both faster and less
|
||||
* prone to memory-leakage bugs than releasing chunks individually.
|
||||
* We organize contexts into context trees to allow fine-grain control
|
||||
* over chunk lifetime while preserving the certainty that we will free
|
||||
* everything that should be freed. See utils/mmgr/README for more info.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: palloc.h,v 1.12 2000/01/26 05:58:38 momjian Exp $
|
||||
* $Id: palloc.h,v 1.13 2000/06/28 03:33:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PALLOC_H
|
||||
#define PALLOC_H
|
||||
|
||||
#ifdef PALLOC_IS_MALLOC
|
||||
|
||||
#define palloc(s) malloc(s)
|
||||
#define pfree(p) free(p)
|
||||
#define repalloc(p,s) realloc((p),(s))
|
||||
|
||||
#else /* ! PALLOC_IS_MALLOC */
|
||||
|
||||
/* ----------
|
||||
* In the case we use memory contexts, use macro's for palloc() etc.
|
||||
* ----------
|
||||
/*
|
||||
* Type MemoryContextData is declared in nodes/memnodes.h. Most users
|
||||
* of memory allocation should just treat it as an abstract type, so we
|
||||
* do not provide the struct contents here.
|
||||
*/
|
||||
#define palloc(s) ((void *)MemoryContextAlloc(CurrentMemoryContext,(Size)(s)))
|
||||
#define pfree(p) MemoryContextFree(CurrentMemoryContext,(Pointer)(p))
|
||||
#define repalloc(p,s) ((void *)MemoryContextRealloc(CurrentMemoryContext,(Pointer)(p),(Size)(s)))
|
||||
typedef struct MemoryContextData *MemoryContext;
|
||||
|
||||
#endif /* PALLOC_IS_MALLOC */
|
||||
/*
|
||||
* CurrentMemoryContext is the default allocation context for palloc().
|
||||
* We declare it here so that palloc() can be a macro. Avoid accessing it
|
||||
* directly! Instead, use MemoryContextSwitchTo() to change the setting.
|
||||
*/
|
||||
extern DLLIMPORT MemoryContext CurrentMemoryContext;
|
||||
|
||||
/*
|
||||
* Fundamental memory-allocation operations (more are in utils/memutils.h)
|
||||
*/
|
||||
extern void *MemoryContextAlloc(MemoryContext context, Size size);
|
||||
|
||||
#define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz))
|
||||
|
||||
extern void pfree(void *pointer);
|
||||
|
||||
extern void *repalloc(void *pointer, Size size);
|
||||
|
||||
extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
|
||||
|
||||
/*
|
||||
* These are like standard strdup() except the copied string is
|
||||
* allocated in a context, not with malloc().
|
||||
*/
|
||||
extern char *MemoryContextStrdup(MemoryContext context, const char *string);
|
||||
|
||||
#define pstrdup(str) MemoryContextStrdup(CurrentMemoryContext, (str))
|
||||
|
||||
|
||||
/* ----------------
|
||||
* Alignment macros: align a length or address appropriately for a given type.
|
||||
*
|
||||
* There used to be some incredibly crufty platform-dependent hackery here,
|
||||
* but now we rely on the configure script to get the info for us. Much nicer.
|
||||
*
|
||||
* NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
|
||||
* That case seems extremely unlikely to occur in practice, however.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
|
||||
|
||||
#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN))
|
||||
#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN))
|
||||
#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN))
|
||||
#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
|
||||
#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
|
||||
|
||||
/* like strdup except uses palloc */
|
||||
extern char *pstrdup(const char *pointer);
|
||||
|
||||
#endif /* PALLOC_H */
|
||||
|
|
|
@ -7,16 +7,14 @@
|
|||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: portal.h,v 1.23 2000/04/12 17:16:55 momjian Exp $
|
||||
* $Id: portal.h,v 1.24 2000/06/28 03:33:33 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
/*
|
||||
* Note:
|
||||
* A portal is an abstraction which represents the execution state of
|
||||
* a running query (or a fixed sequence of queries). The "blank portal" is
|
||||
* a portal with an InvalidName. This blank portal is in existance except
|
||||
* between calls to BlankPortalAssignName and GetPortalByName(NULL).
|
||||
* a running query (or a fixed sequence of queries).
|
||||
*
|
||||
* Note:
|
||||
* now that PQ calls can be made from within a backend, a portal
|
||||
|
@ -29,27 +27,18 @@
|
|||
#include "executor/execdesc.h"
|
||||
#include "nodes/memnodes.h"
|
||||
|
||||
typedef struct PortalBlockData
|
||||
|
||||
typedef struct PortalD *Portal;
|
||||
|
||||
typedef struct PortalD
|
||||
{
|
||||
AllocSetData setData;
|
||||
FixedItemData itemData;
|
||||
} PortalBlockData;
|
||||
|
||||
typedef PortalBlockData *PortalBlock;
|
||||
|
||||
typedef struct PortalD PortalD;
|
||||
typedef PortalD *Portal;
|
||||
|
||||
struct PortalD
|
||||
{
|
||||
char *name; /* XXX PortalName */
|
||||
struct PortalVariableMemoryData variable;
|
||||
struct PortalHeapMemoryData heap;
|
||||
QueryDesc *queryDesc;
|
||||
char *name; /* Portal's name */
|
||||
MemoryContext heap; /* subsidiary memory */
|
||||
QueryDesc *queryDesc; /* Info about query associated with portal */
|
||||
TupleDesc attinfo;
|
||||
EState *state;
|
||||
void (*cleanup) (Portal);
|
||||
};
|
||||
void (*cleanup) (Portal); /* Cleanup routine (optional) */
|
||||
} PortalD;
|
||||
|
||||
/*
|
||||
* PortalIsValid
|
||||
|
@ -57,36 +46,20 @@ struct PortalD
|
|||
*/
|
||||
#define PortalIsValid(p) PointerIsValid(p)
|
||||
|
||||
/*
|
||||
* Special portals (well, their names anyway)
|
||||
*/
|
||||
#define VACPNAME "<vacuum>"
|
||||
#define TRUNCPNAME "<truncate>"
|
||||
|
||||
extern bool PortalNameIsSpecial(char *pname);
|
||||
extern void EnablePortalManager(void);
|
||||
extern void AtEOXact_portals(void);
|
||||
extern void EnablePortalManager(bool on);
|
||||
extern Portal CreatePortal(char *name);
|
||||
extern void PortalDrop(Portal *portalP);
|
||||
extern Portal GetPortalByName(char *name);
|
||||
extern Portal BlankPortalAssignName(char *name);
|
||||
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
|
||||
TupleDesc attinfo, EState *state,
|
||||
void (*cleanup) (Portal portal));
|
||||
extern QueryDesc *PortalGetQueryDesc(Portal portal);
|
||||
extern EState *PortalGetState(Portal portal);
|
||||
extern Portal CreatePortal(char *name);
|
||||
extern void PortalDrop(Portal *portalP);
|
||||
extern void StartPortalAllocMode(AllocMode mode, Size limit);
|
||||
extern void EndPortalAllocMode(void);
|
||||
extern void PortalResetHeapMemory(Portal portal);
|
||||
extern PortalVariableMemory PortalGetVariableMemory(Portal portal);
|
||||
extern PortalHeapMemory PortalGetHeapMemory(Portal portal);
|
||||
extern void CommonSpecialPortalOpen(void);
|
||||
extern void CommonSpecialPortalClose(void);
|
||||
extern PortalVariableMemory CommonSpecialPortalGetMemory(void);
|
||||
extern bool CommonSpecialPortalIsOpen(void);
|
||||
extern MemoryContext PortalGetHeapMemory(Portal portal);
|
||||
|
||||
/* estimate of the maximum number of open portals a user would have,
|
||||
* used in initially sizing the PortalHashTable in EnablePortalManager()
|
||||
* used in initially sizing the PortalHashTable in EnablePortalManager()
|
||||
*/
|
||||
#define PORTALS_PER_USER 10
|
||||
|
||||
|
|
Loading…
Reference in New Issue