mirror of
https://github.com/postgres/postgres.git
synced 2025-06-17 17:02:08 +03:00
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:
@ -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
|
Genetic Optimizer
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer
|
|||||||
<Sect2>
|
<Sect2>
|
||||||
<Title>Basic Improvements</Title>
|
<Title>Basic Improvements</Title>
|
||||||
|
|
||||||
<Sect3>
|
|
||||||
<Title>Improve freeing of memory when query is already processed</Title>
|
|
||||||
|
|
||||||
<Para>
|
|
||||||
With large <Command>join</Command> queries the computing time spent for the genetic query
|
|
||||||
optimization seems to be a mere <Emphasis>fraction</Emphasis> of the time
|
|
||||||
<ProductName>Postgres</ProductName>
|
|
||||||
needs for freeing memory via routine <Function>MemoryContextFree</Function>,
|
|
||||||
file <FileName>backend/utils/mmgr/mcxt.c</FileName>.
|
|
||||||
Debugging showed that it get stucked in a loop of routine
|
|
||||||
<Function>OrderedElemPop</Function>, file <FileName>backend/utils/mmgr/oset.c</FileName>.
|
|
||||||
The same problems arise with long queries when using the normal
|
|
||||||
<ProductName>Postgres</ProductName> query optimization algorithm.
|
|
||||||
</para>
|
|
||||||
</sect3>
|
|
||||||
|
|
||||||
<Sect3>
|
<Sect3>
|
||||||
<Title>Improve genetic algorithm parameter settings</Title>
|
<Title>Improve genetic algorithm parameter settings</Title>
|
||||||
|
|
||||||
|
@ -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
|
Postgres documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -153,12 +153,13 @@ SELECT
|
|||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><computeroutput>
|
<term><computeroutput>
|
||||||
NOTICE
|
NOTICE: Closing pre-existing portal "<replaceable class="parameter">cursorname</replaceable>"
|
||||||
BlankPortalAssignName: portal "<replaceable class="parameter">cursorname</replaceable>" already exists
|
|
||||||
</computeroutput></term>
|
</computeroutput></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
This error occurs if <replaceable class="parameter">cursorname</replaceable> is already declared.
|
This message is reported if the same cursor name was already declared
|
||||||
|
in the current transaction block. The previous definition is
|
||||||
|
discarded.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.55 2000/06/17 00:09:34 petere Exp $
|
# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.56 2000/06/28 03:30:57 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -237,8 +237,6 @@ install-headers: prebuildheaders $(SRCDIR)/include/config.h
|
|||||||
$(HEADERDIR)/utils/fmgroids.h
|
$(HEADERDIR)/utils/fmgroids.h
|
||||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \
|
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \
|
||||||
$(HEADERDIR)/utils/palloc.h
|
$(HEADERDIR)/utils/palloc.h
|
||||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/mcxt.h \
|
|
||||||
$(HEADERDIR)/utils/mcxt.h
|
|
||||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/access/attnum.h \
|
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/access/attnum.h \
|
||||||
$(HEADERDIR)/access/attnum.h
|
$(HEADERDIR)/access/attnum.h
|
||||||
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \
|
$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.71 2000/06/15 04:09:34 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.72 2000/06/28 03:31:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -1230,10 +1230,7 @@ heap_insert(Relation relation, HeapTuple tup)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!OidIsValid(tup->t_data->t_oid))
|
if (!OidIsValid(tup->t_data->t_oid))
|
||||||
{
|
|
||||||
tup->t_data->t_oid = newoid();
|
tup->t_data->t_oid = newoid();
|
||||||
LastOidProcessed = tup->t_data->t_oid;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
CheckMaxObjectId(tup->t_data->t_oid);
|
CheckMaxObjectId(tup->t_data->t_oid);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.67 2000/06/18 22:43:51 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.68 2000/06/28 03:31:05 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Transaction aborts can now occur two ways:
|
* Transaction aborts can now occur two ways:
|
||||||
@ -18,14 +18,14 @@
|
|||||||
*
|
*
|
||||||
* These two cases used to be treated identically, but now
|
* These two cases used to be treated identically, but now
|
||||||
* we need to distinguish them. Why? consider the following
|
* we need to distinguish them. Why? consider the following
|
||||||
* two situatuons:
|
* two situations:
|
||||||
*
|
*
|
||||||
* case 1 case 2
|
* case 1 case 2
|
||||||
* ------ ------
|
* ------ ------
|
||||||
* 1) user types BEGIN 1) user types BEGIN
|
* 1) user types BEGIN 1) user types BEGIN
|
||||||
* 2) user does something 2) user does something
|
* 2) user does something 2) user does something
|
||||||
* 3) user does not like what 3) system aborts for some reason
|
* 3) user does not like what 3) system aborts for some reason
|
||||||
* she shes and types ABORT
|
* she sees and types ABORT
|
||||||
*
|
*
|
||||||
* In case 1, we want to abort the transaction and return to the
|
* In case 1, we want to abort the transaction and return to the
|
||||||
* default state. In case 2, there may be more commands coming
|
* default state. In case 2, there may be more commands coming
|
||||||
@ -42,6 +42,15 @@
|
|||||||
* * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
|
* * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
|
||||||
* * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
|
* * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
|
||||||
*
|
*
|
||||||
|
* Low-level transaction abort handling is divided into two phases:
|
||||||
|
* * AbortTransaction() executes as soon as we realize the transaction
|
||||||
|
* has failed. It should release all shared resources (locks etc)
|
||||||
|
* so that we do not delay other backends unnecessarily.
|
||||||
|
* * CleanupTransaction() executes when we finally see a user COMMIT
|
||||||
|
* or ROLLBACK command; it cleans things up and gets us out of
|
||||||
|
* the transaction internally. In particular, we mustn't destroy
|
||||||
|
* TransactionCommandContext until this point.
|
||||||
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file is an attempt at a redesign of the upper layer
|
* This file is an attempt at a redesign of the upper layer
|
||||||
* of the V1 transaction system which was too poorly thought
|
* of the V1 transaction system which was too poorly thought
|
||||||
@ -70,7 +79,7 @@
|
|||||||
* StartTransaction
|
* StartTransaction
|
||||||
* CommitTransaction
|
* CommitTransaction
|
||||||
* AbortTransaction
|
* AbortTransaction
|
||||||
* UserAbortTransaction
|
* CleanupTransaction
|
||||||
*
|
*
|
||||||
* are provided to do the lower level work like recording
|
* are provided to do the lower level work like recording
|
||||||
* the transaction status in the log and doing memory cleanup.
|
* the transaction status in the log and doing memory cleanup.
|
||||||
@ -151,13 +160,15 @@
|
|||||||
#include "commands/async.h"
|
#include "commands/async.h"
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
#include "commands/trigger.h"
|
#include "commands/trigger.h"
|
||||||
|
#include "executor/spi.h"
|
||||||
#include "libpq/be-fsstubs.h"
|
#include "libpq/be-fsstubs.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/sinval.h"
|
#include "storage/sinval.h"
|
||||||
#include "utils/temprel.h"
|
|
||||||
#include "utils/inval.h"
|
#include "utils/inval.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/portal.h"
|
#include "utils/portal.h"
|
||||||
#include "utils/relcache.h"
|
#include "utils/relcache.h"
|
||||||
|
#include "utils/temprel.h"
|
||||||
|
|
||||||
extern bool SharedBufferChanged;
|
extern bool SharedBufferChanged;
|
||||||
|
|
||||||
@ -165,6 +176,7 @@ static void AbortTransaction(void);
|
|||||||
static void AtAbort_Cache(void);
|
static void AtAbort_Cache(void);
|
||||||
static void AtAbort_Locks(void);
|
static void AtAbort_Locks(void);
|
||||||
static void AtAbort_Memory(void);
|
static void AtAbort_Memory(void);
|
||||||
|
static void AtCleanup_Memory(void);
|
||||||
static void AtCommit_Cache(void);
|
static void AtCommit_Cache(void);
|
||||||
static void AtCommit_LocalCache(void);
|
static void AtCommit_LocalCache(void);
|
||||||
static void AtCommit_Locks(void);
|
static void AtCommit_Locks(void);
|
||||||
@ -172,6 +184,7 @@ static void AtCommit_Memory(void);
|
|||||||
static void AtStart_Cache(void);
|
static void AtStart_Cache(void);
|
||||||
static void AtStart_Locks(void);
|
static void AtStart_Locks(void);
|
||||||
static void AtStart_Memory(void);
|
static void AtStart_Memory(void);
|
||||||
|
static void CleanupTransaction(void);
|
||||||
static void CommitTransaction(void);
|
static void CommitTransaction(void);
|
||||||
static void RecordTransactionAbort(void);
|
static void RecordTransactionAbort(void);
|
||||||
static void RecordTransactionCommit(void);
|
static void RecordTransactionCommit(void);
|
||||||
@ -243,7 +256,7 @@ bool AMI_OVERRIDE = false;
|
|||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* TranactionFlushEnabled()
|
* TranactionFlushEnabled()
|
||||||
* SetTranactionFlushEnabled()
|
* SetTransactionFlushEnabled()
|
||||||
*
|
*
|
||||||
* These are used to test and set the "TransactionFlushState"
|
* These are used to test and set the "TransactionFlushState"
|
||||||
* varable. If this variable is true (the default), then
|
* varable. If this variable is true (the default), then
|
||||||
@ -580,22 +593,35 @@ AtStart_Locks()
|
|||||||
static void
|
static void
|
||||||
AtStart_Memory()
|
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);
|
Assert(TopTransactionContext == NULL);
|
||||||
portalContext = (MemoryContext) PortalGetHeapMemory(portal);
|
Assert(TransactionCommandContext == NULL);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* tell system to allocate in the blank portal context
|
* Create a toplevel context for the transaction.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(portalContext);
|
TopTransactionContext =
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
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
|
static void
|
||||||
AtCommit_Memory()
|
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
|
* Now that we're "out" of a transaction, have the
|
||||||
* system allocate things in the top memory context instead
|
* system allocate things in the top memory context instead
|
||||||
* of the blank portal memory context.
|
* of per-transaction contexts.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(TopMemoryContext);
|
MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Release all transaction-local memory.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
MemoryContextDelete(TopTransactionContext);
|
||||||
|
TopTransactionContext = NULL;
|
||||||
|
TransactionCommandContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@ -798,24 +823,52 @@ AtAbort_Locks()
|
|||||||
static void
|
static void
|
||||||
AtAbort_Memory()
|
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);
|
MemoryContextSwitchTo(TransactionCommandContext);
|
||||||
PortalResetHeapMemory(portal);
|
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* 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
|
* Now that we're "out" of a transaction, have the
|
||||||
* system allocate things in the top memory context instead
|
* system allocate things in the top memory context instead
|
||||||
* of the blank portal memory context.
|
* of per-transaction contexts.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(TopMemoryContext);
|
MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Release all transaction-local memory.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
MemoryContextDelete(TopTransactionContext);
|
||||||
|
TopTransactionContext = NULL;
|
||||||
|
TransactionCommandContext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* interface routines
|
* interface routines
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
@ -854,6 +907,7 @@ StartTransaction()
|
|||||||
s->state = TRANS_START;
|
s->state = TRANS_START;
|
||||||
|
|
||||||
SetReindexProcessing(false);
|
SetReindexProcessing(false);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* generate a new transaction id
|
* generate a new transaction id
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -874,9 +928,9 @@ StartTransaction()
|
|||||||
* initialize the various transaction subsystems
|
* initialize the various transaction subsystems
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
AtStart_Memory();
|
||||||
AtStart_Cache();
|
AtStart_Cache();
|
||||||
AtStart_Locks();
|
AtStart_Locks();
|
||||||
AtStart_Memory();
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Tell the trigger manager to we're starting a transaction
|
* Tell the trigger manager to we're starting a transaction
|
||||||
@ -974,20 +1028,21 @@ CommitTransaction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
RelationPurgeLocalRelation(true);
|
RelationPurgeLocalRelation(true);
|
||||||
|
AtEOXact_SPI();
|
||||||
AtEOXact_nbtree();
|
AtEOXact_nbtree();
|
||||||
AtCommit_Cache();
|
AtCommit_Cache();
|
||||||
AtCommit_Locks();
|
AtCommit_Locks();
|
||||||
AtCommit_Memory();
|
AtCommit_Memory();
|
||||||
AtEOXact_Files();
|
AtEOXact_Files();
|
||||||
|
|
||||||
|
SharedBufferChanged = false; /* safest place to do it */
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* done with commit processing, set current transaction
|
* done with commit processing, set current transaction
|
||||||
* state back to default
|
* state back to default
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_DEFAULT;
|
s->state = TRANS_DEFAULT;
|
||||||
SharedBufferChanged = false;/* safest place to do it */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -1018,7 +1073,7 @@ AbortTransaction()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (s->state != TRANS_INPROGRESS)
|
if (s->state != TRANS_INPROGRESS)
|
||||||
elog(NOTICE, "AbortTransaction and not in in-progress state ");
|
elog(NOTICE, "AbortTransaction and not in in-progress state");
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Tell the trigger manager that this transaction is about to be
|
* Tell the trigger manager that this transaction is about to be
|
||||||
@ -1043,24 +1098,56 @@ AbortTransaction()
|
|||||||
AtAbort_Notify();
|
AtAbort_Notify();
|
||||||
CloseSequences();
|
CloseSequences();
|
||||||
AtEOXact_portals();
|
AtEOXact_portals();
|
||||||
if (CommonSpecialPortalIsOpen())
|
|
||||||
CommonSpecialPortalClose();
|
|
||||||
RecordTransactionAbort();
|
RecordTransactionAbort();
|
||||||
RelationPurgeLocalRelation(false);
|
RelationPurgeLocalRelation(false);
|
||||||
invalidate_temp_relations();
|
invalidate_temp_relations();
|
||||||
|
AtEOXact_SPI();
|
||||||
AtEOXact_nbtree();
|
AtEOXact_nbtree();
|
||||||
AtAbort_Cache();
|
AtAbort_Cache();
|
||||||
AtAbort_Locks();
|
AtAbort_Locks();
|
||||||
AtAbort_Memory();
|
AtAbort_Memory();
|
||||||
AtEOXact_Files();
|
AtEOXact_Files();
|
||||||
|
|
||||||
|
SharedBufferChanged = false; /* safest place to do it */
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* State remains TRANS_ABORT until CleanupTransaction().
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------
|
||||||
|
* CleanupTransaction
|
||||||
|
*
|
||||||
|
* --------------------------------
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
CleanupTransaction()
|
||||||
|
{
|
||||||
|
TransactionState s = CurrentTransactionState;
|
||||||
|
|
||||||
|
if (s->state == TRANS_DISABLED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* State should still be TRANS_ABORT from AbortTransaction().
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
if (s->state != TRANS_ABORT)
|
||||||
|
elog(FATAL, "CleanupTransaction and not in abort state");
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* do abort cleanup processing
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
AtCleanup_Memory();
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* done with abort processing, set current transaction
|
* done with abort processing, set current transaction
|
||||||
* state back to default
|
* state back to default
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
s->state = TRANS_DEFAULT;
|
s->state = TRANS_DEFAULT;
|
||||||
SharedBufferChanged = false;/* safest place to do it */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -1133,7 +1220,7 @@ StartTransactionCommand()
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* This means we somehow aborted and the last call to
|
* This means we somehow aborted and the last call to
|
||||||
* CommitTransactionCommand() didn't clear the state so
|
* CommitTransactionCommand() didn't clear the state so
|
||||||
* we remain in the ENDABORT state and mabey next time
|
* we remain in the ENDABORT state and maybe next time
|
||||||
* we get to CommitTransactionCommand() the state will
|
* we get to CommitTransactionCommand() the state will
|
||||||
* get reset to default.
|
* get reset to default.
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -1142,6 +1229,13 @@ StartTransactionCommand()
|
|||||||
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
|
elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must switch to TransactionCommandContext before returning.
|
||||||
|
* This is already done if we called StartTransaction, otherwise not.
|
||||||
|
*/
|
||||||
|
Assert(TransactionCommandContext != NULL);
|
||||||
|
MemoryContextSwitchTo(TransactionCommandContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -1181,28 +1275,25 @@ CommitTransactionCommand()
|
|||||||
* command counter and return. Someday we may free resources
|
* command counter and return. Someday we may free resources
|
||||||
* local to the command.
|
* local to the command.
|
||||||
*
|
*
|
||||||
* That someday is today, at least for memory allocated by
|
* That someday is today, at least for memory allocated in
|
||||||
* command in the BlankPortal' HeapMemory context.
|
* TransactionCommandContext.
|
||||||
* - vadim 03/25/97
|
* - vadim 03/25/97
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
case TBLOCK_INPROGRESS:
|
case TBLOCK_INPROGRESS:
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
#ifdef TBL_FREE_CMD_MEMORY
|
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
||||||
EndPortalAllocMode();
|
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* This is the case when we just got the "END TRANSACTION"
|
* This is the case when we just got the "END TRANSACTION"
|
||||||
* statement, so we go back to the default state and
|
* statement, so we commit the transaction and go back to
|
||||||
* commit the transaction.
|
* the default state.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
case TBLOCK_END:
|
case TBLOCK_END:
|
||||||
s->blockState = TBLOCK_DEFAULT;
|
|
||||||
CommitTransaction();
|
CommitTransaction();
|
||||||
|
s->blockState = TBLOCK_DEFAULT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -1218,10 +1309,11 @@ CommitTransactionCommand()
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* Here we were in an aborted transaction block which
|
* Here we were in an aborted transaction block which
|
||||||
* just processed the "END TRANSACTION" command from the
|
* just processed the "END TRANSACTION" command from the
|
||||||
* user, so now we return the to default state.
|
* user, so clean up and return to the default state.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ENDABORT:
|
case TBLOCK_ENDABORT:
|
||||||
|
CleanupTransaction();
|
||||||
s->blockState = TBLOCK_DEFAULT;
|
s->blockState = TBLOCK_DEFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1240,11 +1332,12 @@ AbortCurrentTransaction()
|
|||||||
{
|
{
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* if we aren't in a transaction block, we
|
* if we aren't in a transaction block, we
|
||||||
* just do our usual abort transaction.
|
* just do the basic abort & cleanup transaction.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
case TBLOCK_DEFAULT:
|
case TBLOCK_DEFAULT:
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
CleanupTransaction();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -1257,6 +1350,7 @@ AbortCurrentTransaction()
|
|||||||
case TBLOCK_BEGIN:
|
case TBLOCK_BEGIN:
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -1269,6 +1363,7 @@ AbortCurrentTransaction()
|
|||||||
case TBLOCK_INPROGRESS:
|
case TBLOCK_INPROGRESS:
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
/* CleanupTransaction happens when we exit TBLOCK_ABORT */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -1281,6 +1376,7 @@ AbortCurrentTransaction()
|
|||||||
case TBLOCK_END:
|
case TBLOCK_END:
|
||||||
s->blockState = TBLOCK_DEFAULT;
|
s->blockState = TBLOCK_DEFAULT;
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
CleanupTransaction();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -1297,10 +1393,11 @@ AbortCurrentTransaction()
|
|||||||
* Here we were in an aborted transaction block which
|
* Here we were in an aborted transaction block which
|
||||||
* just processed the "END TRANSACTION" command but somehow
|
* just processed the "END TRANSACTION" command but somehow
|
||||||
* aborted again.. since we must have done the abort
|
* aborted again.. since we must have done the abort
|
||||||
* processing, we return to the default state.
|
* processing, we clean up and return to the default state.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
case TBLOCK_ENDABORT:
|
case TBLOCK_ENDABORT:
|
||||||
|
CleanupTransaction();
|
||||||
s->blockState = TBLOCK_DEFAULT;
|
s->blockState = TBLOCK_DEFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1394,13 +1491,14 @@ EndTransactionBlock(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* We should not get here, but if we do, we go to the ENDABORT
|
* here, the user issued COMMIT when not inside a transaction.
|
||||||
* state after printing a warning. The upcoming call to
|
* Issue a notice and go to abort state. The upcoming call to
|
||||||
* CommitTransactionCommand() will then put us back into the
|
* CommitTransactionCommand() will then put us back into the
|
||||||
* default state.
|
* default state.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
elog(NOTICE, "COMMIT: no transaction in progress");
|
elog(NOTICE, "COMMIT: no transaction in progress");
|
||||||
|
AbortTransaction();
|
||||||
s->blockState = TBLOCK_ENDABORT;
|
s->blockState = TBLOCK_ENDABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1427,29 +1525,23 @@ AbortTransactionBlock(void)
|
|||||||
* here we were inside a transaction block something
|
* here we were inside a transaction block something
|
||||||
* screwed up inside the system so we enter the abort state,
|
* screwed up inside the system so we enter the abort state,
|
||||||
* do the abort processing and then return.
|
* do the abort processing and then return.
|
||||||
* We remain in the abort state until we see the upcoming
|
* We remain in the abort state until we see an
|
||||||
* END TRANSACTION command.
|
* END TRANSACTION command.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* do abort processing and return
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* this case should not be possible, because it would mean
|
* here, the user issued ABORT when not inside a transaction.
|
||||||
* the user entered an "abort" from outside a transaction block.
|
* Issue a notice and go to abort state. The upcoming call to
|
||||||
* So we print an error message, abort the transaction and
|
* CommitTransactionCommand() will then put us back into the
|
||||||
* enter the "ENDABORT" state so we will end up in the default
|
* default state.
|
||||||
* state after the upcoming CommitTransactionCommand().
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
|
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
s->blockState = TBLOCK_ENDABORT;
|
s->blockState = TBLOCK_ENDABORT;
|
||||||
}
|
}
|
||||||
@ -1495,27 +1587,16 @@ UserAbortTransactionBlock()
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
s->blockState = TBLOCK_ABORT;
|
s->blockState = TBLOCK_ABORT;
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* do abort processing
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* change to the end abort state and return
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
s->blockState = TBLOCK_ENDABORT;
|
s->blockState = TBLOCK_ENDABORT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* this case should not be possible, because it would mean
|
* here, the user issued ABORT when not inside a transaction.
|
||||||
* the user entered a "rollback" from outside a transaction block.
|
* Issue a notice and go to abort state. The upcoming call to
|
||||||
* So we print an error message, abort the transaction and
|
* CommitTransactionCommand() will then put us back into the
|
||||||
* enter the "ENDABORT" state so we will end up in the default
|
* default state.
|
||||||
* state after the upcoming CommitTransactionCommand().
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
elog(NOTICE, "ROLLBACK: no transaction in progress");
|
||||||
@ -1540,7 +1621,10 @@ AbortOutOfAnyTransaction()
|
|||||||
* Get out of any low-level transaction
|
* Get out of any low-level transaction
|
||||||
*/
|
*/
|
||||||
if (s->state != TRANS_DEFAULT)
|
if (s->state != TRANS_DEFAULT)
|
||||||
|
{
|
||||||
AbortTransaction();
|
AbortTransaction();
|
||||||
|
CleanupTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now reset the high-level state
|
* Now reset the high-level state
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.87 2000/06/22 22:31:17 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.88 2000/06/28 03:31:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -34,14 +34,14 @@
|
|||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "tcop/tcopprot.h"
|
#include "tcop/tcopprot.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/exc.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/portal.h"
|
|
||||||
|
|
||||||
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
|
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
|
||||||
|
|
||||||
extern void BaseInit(void);
|
|
||||||
extern void StartupXLOG(void);
|
extern void StartupXLOG(void);
|
||||||
extern void ShutdownXLOG(void);
|
extern void ShutdownXLOG(void);
|
||||||
extern void BootStrapXLOG(void);
|
extern void BootStrapXLOG(void);
|
||||||
@ -144,8 +144,8 @@ static Datum values[MAXATTR]; /* corresponding attribute values */
|
|||||||
int numattr; /* number of attributes for cur. rel */
|
int numattr; /* number of attributes for cur. rel */
|
||||||
|
|
||||||
int DebugMode;
|
int DebugMode;
|
||||||
static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
|
|
||||||
* context */
|
static MemoryContext nogc = NULL; /* special no-gc mem context */
|
||||||
|
|
||||||
extern int optind;
|
extern int optind;
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
@ -240,6 +240,17 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
|
|
||||||
MyProcPid = getpid();
|
MyProcPid = getpid();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fire up essential subsystems: error and memory management
|
||||||
|
*
|
||||||
|
* If we are running under the postmaster, this is done already.
|
||||||
|
*/
|
||||||
|
if (!IsUnderPostmaster)
|
||||||
|
{
|
||||||
|
EnableExceptionHandling(true);
|
||||||
|
MemoryContextInit();
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* process command arguments
|
* process command arguments
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -428,7 +439,6 @@ boot_openrel(char *relname)
|
|||||||
|
|
||||||
if (Typ == (struct typmap **) NULL)
|
if (Typ == (struct typmap **) NULL)
|
||||||
{
|
{
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
|
||||||
rel = heap_openr(TypeRelationName, NoLock);
|
rel = heap_openr(TypeRelationName, NoLock);
|
||||||
Assert(rel);
|
Assert(rel);
|
||||||
scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
|
scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
|
||||||
@ -445,13 +455,13 @@ boot_openrel(char *relname)
|
|||||||
while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
|
while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
|
||||||
{
|
{
|
||||||
(*app)->am_oid = tup->t_data->t_oid;
|
(*app)->am_oid = tup->t_data->t_oid;
|
||||||
memmove((char *) &(*app++)->am_typ,
|
memcpy((char *) &(*app)->am_typ,
|
||||||
(char *) GETSTRUCT(tup),
|
(char *) GETSTRUCT(tup),
|
||||||
sizeof((*app)->am_typ));
|
sizeof((*app)->am_typ));
|
||||||
|
app++;
|
||||||
}
|
}
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
EndPortalAllocMode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reldesc != NULL)
|
if (reldesc != NULL)
|
||||||
@ -1088,10 +1098,14 @@ index_register(char *heap,
|
|||||||
* them later.
|
* them later.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (nogc == (GlobalMemory) NULL)
|
if (nogc == NULL)
|
||||||
nogc = CreateGlobalMemory("BootstrapNoGC");
|
nogc = AllocSetContextCreate((MemoryContext) NULL,
|
||||||
|
"BootstrapNoGC",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
|
oldcxt = MemoryContextSwitchTo(nogc);
|
||||||
|
|
||||||
newind = (IndexList *) palloc(sizeof(IndexList));
|
newind = (IndexList *) palloc(sizeof(IndexList));
|
||||||
newind->il_heap = pstrdup(heap);
|
newind->il_heap = pstrdup(heap);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.133 2000/06/18 22:43:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.134 2000/06/28 03:31:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -188,38 +188,27 @@ heap_create(char *relname,
|
|||||||
relname);
|
relname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* switch to the cache context so that we don't lose
|
|
||||||
* allocations at the end of this transaction, I guess.
|
|
||||||
* -cim 6/14/90
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
if (!CacheCxt)
|
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* real ugly stuff to assign the proper relid in the relation
|
* real ugly stuff to assign the proper relid in the relation
|
||||||
* descriptor follows.
|
* descriptor follows.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (relname && !strcmp(RelationRelationName, relname))
|
if (relname && strcmp(RelationRelationName, relname) == 0)
|
||||||
{
|
{
|
||||||
relid = RelOid_pg_class;
|
relid = RelOid_pg_class;
|
||||||
nailme = true;
|
nailme = true;
|
||||||
}
|
}
|
||||||
else if (relname && !strcmp(AttributeRelationName, relname))
|
else if (relname && strcmp(AttributeRelationName, relname) == 0)
|
||||||
{
|
{
|
||||||
relid = RelOid_pg_attribute;
|
relid = RelOid_pg_attribute;
|
||||||
nailme = true;
|
nailme = true;
|
||||||
}
|
}
|
||||||
else if (relname && !strcmp(ProcedureRelationName, relname))
|
else if (relname && strcmp(ProcedureRelationName, relname) == 0)
|
||||||
{
|
{
|
||||||
relid = RelOid_pg_proc;
|
relid = RelOid_pg_proc;
|
||||||
nailme = true;
|
nailme = true;
|
||||||
}
|
}
|
||||||
else if (relname && !strcmp(TypeRelationName, relname))
|
else if (relname && strcmp(TypeRelationName, relname) == 0)
|
||||||
{
|
{
|
||||||
relid = RelOid_pg_type;
|
relid = RelOid_pg_type;
|
||||||
nailme = true;
|
nailme = true;
|
||||||
@ -234,6 +223,15 @@ heap_create(char *relname,
|
|||||||
(int) MyProcPid, uniqueId++);
|
(int) MyProcPid, uniqueId++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* switch to the cache context to create the relcache entry.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
if (!CacheMemoryContext)
|
||||||
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* allocate a new relation descriptor.
|
* allocate a new relation descriptor.
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -287,6 +285,8 @@ heap_create(char *relname,
|
|||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* have the storage manager create the relation.
|
* have the storage manager create the relation.
|
||||||
|
*
|
||||||
|
* XXX shouldn't we switch out of CacheMemoryContext for that?
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.119 2000/06/18 22:43:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.120 2000/06/28 03:31:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -442,10 +442,10 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
|||||||
* context changes
|
* context changes
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
|
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
|
||||||
|
|
||||||
@ -904,16 +904,16 @@ InitIndexStrategy(int numatts,
|
|||||||
* it will be lost at the end of the transaction.
|
* it will be lost at the end of the transaction.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
strategy = (IndexStrategy)
|
strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
|
||||||
MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
|
strsize);
|
||||||
|
|
||||||
if (amsupport > 0)
|
if (amsupport > 0)
|
||||||
{
|
{
|
||||||
strsize = numatts * (amsupport * sizeof(RegProcedure));
|
strsize = numatts * (amsupport * sizeof(RegProcedure));
|
||||||
support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
|
support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
|
||||||
strsize);
|
strsize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.44 2000/06/14 04:53:44 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.45 2000/06/28 03:31:23 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -217,8 +217,7 @@ ProcedureCreate(char *procedureName,
|
|||||||
|
|
||||||
if (languageObjectId == SQLlanguageId)
|
if (languageObjectId == SQLlanguageId)
|
||||||
{
|
{
|
||||||
querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount,
|
querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount);
|
||||||
FALSE);
|
|
||||||
/* typecheck return value */
|
/* typecheck return value */
|
||||||
pg_checkretval(typeObjectId, querytree_list);
|
pg_checkretval(typeObjectId, querytree_list);
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,9 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.80 2000/06/15 04:09:45 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.81 2000/06/28 03:31:28 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PortalExecutorHeapMemory crap needs to be eliminated
|
|
||||||
* by designing a better executor / portal processing memory
|
|
||||||
* interface.
|
|
||||||
*
|
|
||||||
* The PerformAddAttribute() code, like most of the relation
|
* The PerformAddAttribute() code, like most of the relation
|
||||||
* manipulating code in the commands/ directory, should go
|
* manipulating code in the commands/ directory, should go
|
||||||
* someplace closer to the lib/catalog code.
|
* someplace closer to the lib/catalog code.
|
||||||
@ -40,13 +36,6 @@
|
|||||||
#include "parser/parse.h"
|
#include "parser/parse.h"
|
||||||
#endif /* _DROP_COLUMN_HACK__ */
|
#endif /* _DROP_COLUMN_HACK__ */
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalExecutorHeapMemory stuff
|
|
||||||
*
|
|
||||||
* This is where the XXXSuperDuperHacky code was. -cim 3/15/90
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
MemoryContext PortalExecutorHeapMemory = NULL;
|
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* PortalCleanup
|
* PortalCleanup
|
||||||
@ -55,7 +44,7 @@ MemoryContext PortalExecutorHeapMemory = NULL;
|
|||||||
void
|
void
|
||||||
PortalCleanup(Portal portal)
|
PortalCleanup(Portal portal)
|
||||||
{
|
{
|
||||||
MemoryContext context;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* sanity checks
|
* sanity checks
|
||||||
@ -68,8 +57,7 @@ PortalCleanup(Portal portal)
|
|||||||
* set proper portal-executor context before calling ExecMain.
|
* set proper portal-executor context before calling ExecMain.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* tell the executor to shutdown the query
|
* tell the executor to shutdown the query
|
||||||
@ -81,8 +69,7 @@ PortalCleanup(Portal portal)
|
|||||||
* switch back to previous context
|
* switch back to previous context
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(context);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
PortalExecutorHeapMemory = (MemoryContext) NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -99,7 +86,7 @@ PerformPortalFetch(char *name,
|
|||||||
Portal portal;
|
Portal portal;
|
||||||
int feature;
|
int feature;
|
||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
MemoryContext context;
|
MemoryContext oldcontext;
|
||||||
Const limcount;
|
Const limcount;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -108,7 +95,7 @@ PerformPortalFetch(char *name,
|
|||||||
*/
|
*/
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
{
|
{
|
||||||
elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
|
elog(NOTICE, "PerformPortalFetch: missing portal name");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +107,11 @@ PerformPortalFetch(char *name,
|
|||||||
limcount.type = T_Const;
|
limcount.type = T_Const;
|
||||||
limcount.consttype = INT4OID;
|
limcount.consttype = INT4OID;
|
||||||
limcount.constlen = sizeof(int4);
|
limcount.constlen = sizeof(int4);
|
||||||
limcount.constvalue = (Datum) count;
|
limcount.constvalue = Int32GetDatum(count);
|
||||||
limcount.constisnull = FALSE;
|
limcount.constisnull = false;
|
||||||
limcount.constbyval = TRUE;
|
limcount.constbyval = true;
|
||||||
limcount.constisset = FALSE;
|
limcount.constisset = false;
|
||||||
limcount.constiscast = FALSE;
|
limcount.constiscast = false;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* get the portal from the portal name
|
* get the portal from the portal name
|
||||||
@ -143,9 +129,7 @@ PerformPortalFetch(char *name,
|
|||||||
* switch into the portal context
|
* switch into the portal context
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* setup "feature" to tell the executor what direction and
|
* setup "feature" to tell the executor what direction and
|
||||||
@ -174,8 +158,7 @@ PerformPortalFetch(char *name,
|
|||||||
|
|
||||||
BeginCommand(name,
|
BeginCommand(name,
|
||||||
queryDesc->operation,
|
queryDesc->operation,
|
||||||
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
|
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc) */
|
||||||
* */
|
|
||||||
false, /* portal fetches don't end up in
|
false, /* portal fetches don't end up in
|
||||||
* relations */
|
* relations */
|
||||||
false, /* this is a portal fetch, not a "retrieve
|
false, /* this is a portal fetch, not a "retrieve
|
||||||
@ -187,8 +170,6 @@ PerformPortalFetch(char *name,
|
|||||||
* execute the portal fetch operation
|
* execute the portal fetch operation
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
|
|
||||||
|
|
||||||
ExecutorRun(queryDesc, PortalGetState(portal), feature,
|
ExecutorRun(queryDesc, PortalGetState(portal), feature,
|
||||||
(Node *) NULL, (Node *) &limcount);
|
(Node *) NULL, (Node *) &limcount);
|
||||||
|
|
||||||
@ -196,18 +177,16 @@ PerformPortalFetch(char *name,
|
|||||||
pfree(queryDesc);
|
pfree(queryDesc);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Note: the "end-of-command" tag is returned by higher-level
|
* Switch back to old context.
|
||||||
* utility code
|
* ----------------
|
||||||
*
|
*/
|
||||||
* Return blank portal for now.
|
MemoryContextSwitchTo(oldcontext);
|
||||||
* 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
|
* Note: the "end-of-command" tag is returned by higher-level
|
||||||
* do what is possible across transaction boundries.
|
* utility code
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(
|
|
||||||
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
@ -225,15 +204,10 @@ PerformPortalClose(char *name, CommandDest dest)
|
|||||||
*/
|
*/
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
{
|
{
|
||||||
elog(NOTICE, "PerformPortalClose: blank portal unsupported");
|
elog(NOTICE, "PerformPortalClose: missing portal name");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PortalNameIsSpecial(name))
|
|
||||||
elog(ERROR,
|
|
||||||
"The portal name \"%s\" is reserved for internal use",
|
|
||||||
name);
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* get the portal from the portal name
|
* get the portal from the portal name
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.31 2000/06/17 23:41:36 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.32 2000/06/28 03:31:28 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -39,7 +39,6 @@
|
|||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "miscadmin.h" /* ReindexDatabase() */
|
#include "miscadmin.h" /* ReindexDatabase() */
|
||||||
#include "utils/portal.h" /* ReindexDatabase() */
|
|
||||||
#include "catalog/catalog.h" /* ReindexDatabase() */
|
#include "catalog/catalog.h" /* ReindexDatabase() */
|
||||||
|
|
||||||
#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
|
#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
|
||||||
@ -764,7 +763,6 @@ ReindexTable(const char *name, bool force)
|
|||||||
* "ERROR" if table nonexistent.
|
* "ERROR" if table nonexistent.
|
||||||
* ...
|
* ...
|
||||||
*/
|
*/
|
||||||
extern Oid MyDatabaseId;
|
|
||||||
void
|
void
|
||||||
ReindexDatabase(const char *dbname, bool force, bool all)
|
ReindexDatabase(const char *dbname, bool force, bool all)
|
||||||
{
|
{
|
||||||
@ -780,7 +778,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||||||
Oid db_id;
|
Oid db_id;
|
||||||
char *username;
|
char *username;
|
||||||
ScanKeyData scankey;
|
ScanKeyData scankey;
|
||||||
PortalVariableMemory pmem;
|
MemoryContext private_context;
|
||||||
MemoryContext old;
|
MemoryContext old;
|
||||||
int relcnt,
|
int relcnt,
|
||||||
relalc,
|
relalc,
|
||||||
@ -808,16 +806,34 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||||||
db_id = dbtuple->t_data->t_oid;
|
db_id = dbtuple->t_data->t_oid;
|
||||||
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
|
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
|
heap_close(relation, NoLock);
|
||||||
|
|
||||||
if (user_id != db_owner && !superuser)
|
if (user_id != db_owner && !superuser)
|
||||||
elog(ERROR, "REINDEX DATABASE: Permission denied.");
|
elog(ERROR, "REINDEX DATABASE: Permission denied.");
|
||||||
|
|
||||||
if (db_id != MyDatabaseId)
|
if (db_id != MyDatabaseId)
|
||||||
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
|
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
|
||||||
|
|
||||||
heap_close(relation, NoLock);
|
/*
|
||||||
|
* We cannot run inside a user transaction block; if we were
|
||||||
|
* inside a transaction, then our commit- and
|
||||||
|
* start-transaction-command calls would not have the intended effect!
|
||||||
|
*/
|
||||||
|
if (IsTransactionBlock())
|
||||||
|
elog(ERROR, "REINDEX DATABASE cannot run inside a BEGIN/END block");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a memory context that will survive forced transaction commits
|
||||||
|
* we do below. Since it is a child of QueryContext, it will go away
|
||||||
|
* eventually even if we suffer an error; there's no need for special
|
||||||
|
* abort cleanup logic.
|
||||||
|
*/
|
||||||
|
private_context = AllocSetContextCreate(QueryContext,
|
||||||
|
"ReindexDatabase",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
CommonSpecialPortalOpen();
|
|
||||||
pmem = CommonSpecialPortalGetMemory();
|
|
||||||
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
|
relationRelation = heap_openr(RelationRelationName, AccessShareLock);
|
||||||
scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL);
|
scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL);
|
||||||
relcnt = relalc = 0;
|
relcnt = relalc = 0;
|
||||||
@ -832,7 +848,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||||||
}
|
}
|
||||||
if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
|
if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
|
||||||
{
|
{
|
||||||
old = MemoryContextSwitchTo((MemoryContext) pmem);
|
old = MemoryContextSwitchTo(private_context);
|
||||||
if (relcnt == 0)
|
if (relcnt == 0)
|
||||||
{
|
{
|
||||||
relalc = oncealc;
|
relalc = oncealc;
|
||||||
@ -859,6 +875,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
|||||||
elog(NOTICE, "relation %d was reindexed", relids[i]);
|
elog(NOTICE, "relation %d was reindexed", relids[i]);
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
}
|
}
|
||||||
CommonSpecialPortalClose();
|
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
|
|
||||||
|
MemoryContextDelete(private_context);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.69 2000/06/08 22:37:01 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.70 2000/06/28 03:31:28 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1029,8 +1029,8 @@ ltrmark:;
|
|||||||
* end.
|
* end.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static GlobalMemory deftrig_gcxt = NULL;
|
static MemoryContext deftrig_gcxt = NULL;
|
||||||
static GlobalMemory deftrig_cxt = NULL;
|
static MemoryContext deftrig_cxt = NULL;
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Global data that tells which triggers are actually in
|
* Global data that tells which triggers are actually in
|
||||||
@ -1104,7 +1104,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
|
|||||||
* as the current and return that.
|
* as the current and return that.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
trigstate = (DeferredTriggerStatus)
|
trigstate = (DeferredTriggerStatus)
|
||||||
palloc(sizeof(DeferredTriggerStatusData));
|
palloc(sizeof(DeferredTriggerStatusData));
|
||||||
@ -1366,7 +1366,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
|||||||
int
|
int
|
||||||
DeferredTriggerInit(void)
|
DeferredTriggerInit(void)
|
||||||
{
|
{
|
||||||
deftrig_gcxt = CreateGlobalMemory("DeferredTriggerSession");
|
deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"DeferredTriggerSession",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1395,8 +1400,12 @@ DeferredTriggerBeginXact(void)
|
|||||||
* from the per session context to here.
|
* from the per session context to here.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
deftrig_cxt = CreateGlobalMemory("DeferredTriggerXact");
|
deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
"DeferredTriggerXact",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
deftrig_all_isset = deftrig_dfl_all_isset;
|
deftrig_all_isset = deftrig_dfl_all_isset;
|
||||||
deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
|
deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
|
||||||
@ -1461,7 +1470,7 @@ DeferredTriggerEndXact(void)
|
|||||||
|
|
||||||
deferredTriggerInvokeEvents(false);
|
deferredTriggerInvokeEvents(false);
|
||||||
|
|
||||||
GlobalMemoryDestroy(deftrig_cxt);
|
MemoryContextDelete(deftrig_cxt);
|
||||||
deftrig_cxt = NULL;
|
deftrig_cxt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1484,7 +1493,7 @@ DeferredTriggerAbortXact(void)
|
|||||||
if (deftrig_cxt == NULL)
|
if (deftrig_cxt == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GlobalMemoryDestroy(deftrig_cxt);
|
MemoryContextDelete(deftrig_cxt);
|
||||||
deftrig_cxt = NULL;
|
deftrig_cxt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1521,7 +1530,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
* ... outside of a transaction block
|
* ... outside of a transaction block
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Drop all information about individual trigger states per
|
* Drop all information about individual trigger states per
|
||||||
@ -1555,7 +1564,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
* ... inside of a transaction block
|
* ... inside of a transaction block
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* Drop all information about individual trigger states per
|
* Drop all information about individual trigger states per
|
||||||
@ -1701,7 +1710,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
* states of individual triggers on session level.
|
* states of individual triggers on session level.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
|
||||||
|
|
||||||
foreach(l, loid)
|
foreach(l, loid)
|
||||||
{
|
{
|
||||||
@ -1739,7 +1748,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
|||||||
* states of individual triggers on transaction level.
|
* states of individual triggers on transaction level.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
foreach(l, loid)
|
foreach(l, loid)
|
||||||
{
|
{
|
||||||
@ -1827,7 +1836,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
* Create a new event
|
* Create a new event
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
|
|
||||||
ntriggers = rel->trigdesc->n_after_row[event];
|
ntriggers = rel->trigdesc->n_after_row[event];
|
||||||
triggers = rel->trigdesc->tg_after_row[event];
|
triggers = rel->trigdesc->tg_after_row[event];
|
||||||
@ -2022,7 +2031,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
|||||||
* Anything's fine up to here. Add the new event to the queue.
|
* Anything's fine up to here. Add the new event to the queue.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
|
oldcxt = MemoryContextSwitchTo(deftrig_cxt);
|
||||||
deferredTriggerAddEvent(new_event);
|
deferredTriggerAddEvent(new_event);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* user.c
|
* user.c
|
||||||
* use pg_exec_query to create a new user in the catalog
|
* Commands for manipulating users and groups.
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.61 2000/06/25 14:24:59 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.62 2000/06/28 03:31:28 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.161 2000/06/28 03:31:28 tgl Exp $
|
||||||
*
|
*
|
||||||
|
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
@ -35,7 +35,6 @@
|
|||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/inval.h"
|
#include "utils/inval.h"
|
||||||
#include "utils/portal.h"
|
|
||||||
#include "utils/relcache.h"
|
#include "utils/relcache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "utils/temprel.h"
|
#include "utils/temprel.h"
|
||||||
@ -48,9 +47,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bool CommonSpecialPortalInUse = false;
|
static MemoryContext vac_context = NULL;
|
||||||
|
|
||||||
static Portal vac_portal;
|
|
||||||
|
|
||||||
static int MESSAGE_LEVEL; /* message level */
|
static int MESSAGE_LEVEL; /* message level */
|
||||||
|
|
||||||
@ -82,14 +79,13 @@ static int vac_cmp_offno(const void *left, const void *right);
|
|||||||
static int vac_cmp_vtlinks(const void *left, const void *right);
|
static int vac_cmp_vtlinks(const void *left, const void *right);
|
||||||
static bool enough_space(VacPage vacpage, Size len);
|
static bool enough_space(VacPage vacpage, Size len);
|
||||||
static char *show_rusage(struct rusage * ru0);
|
static char *show_rusage(struct rusage * ru0);
|
||||||
/* CommonSpecialPortal function at the bottom */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
||||||
{
|
{
|
||||||
NameData VacRel;
|
NameData VacRel;
|
||||||
Name VacRelName;
|
Name VacRelName;
|
||||||
PortalVariableMemory pmem;
|
|
||||||
MemoryContext old;
|
MemoryContext old;
|
||||||
List *le;
|
List *le;
|
||||||
List *anal_cols2 = NIL;
|
List *anal_cols2 = NIL;
|
||||||
@ -114,8 +110,18 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
|||||||
else
|
else
|
||||||
MESSAGE_LEVEL = DEBUG;
|
MESSAGE_LEVEL = DEBUG;
|
||||||
|
|
||||||
/* Create special portal for cross-transaction storage */
|
/*
|
||||||
CommonSpecialPortalOpen();
|
* Create special memory context for cross-transaction storage.
|
||||||
|
*
|
||||||
|
* Since it is a child of QueryContext, it will go away eventually
|
||||||
|
* even if we suffer an error; there's no need for special abort
|
||||||
|
* cleanup logic.
|
||||||
|
*/
|
||||||
|
vac_context = AllocSetContextCreate(QueryContext,
|
||||||
|
"Vacuum",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/* vacrel gets de-allocated on xact commit, so copy it to safe storage */
|
/* vacrel gets de-allocated on xact commit, so copy it to safe storage */
|
||||||
if (vacrel)
|
if (vacrel)
|
||||||
@ -127,8 +133,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
|||||||
VacRelName = NULL;
|
VacRelName = NULL;
|
||||||
|
|
||||||
/* must also copy the column list, if any, to safe storage */
|
/* must also copy the column list, if any, to safe storage */
|
||||||
pmem = CommonSpecialPortalGetMemory();
|
old = MemoryContextSwitchTo(vac_context);
|
||||||
old = MemoryContextSwitchTo((MemoryContext) pmem);
|
|
||||||
foreach(le, anal_cols)
|
foreach(le, anal_cols)
|
||||||
{
|
{
|
||||||
char *col = (char *) lfirst(le);
|
char *col = (char *) lfirst(le);
|
||||||
@ -198,11 +203,16 @@ vacuum_shutdown()
|
|||||||
*/
|
*/
|
||||||
unlink(RELCACHE_INIT_FILENAME);
|
unlink(RELCACHE_INIT_FILENAME);
|
||||||
|
|
||||||
/* Clean up working storage */
|
|
||||||
CommonSpecialPortalClose();
|
|
||||||
|
|
||||||
/* matches the CommitTransaction in PostgresMain() */
|
/* matches the CommitTransaction in PostgresMain() */
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up working storage --- note we must do this after
|
||||||
|
* StartTransactionCommand, else we might be trying to delete
|
||||||
|
* the active context!
|
||||||
|
*/
|
||||||
|
MemoryContextDelete(vac_context);
|
||||||
|
vac_context = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -239,8 +249,6 @@ getrels(NameData *VacRelP)
|
|||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
PortalVariableMemory portalmem;
|
|
||||||
MemoryContext old;
|
|
||||||
VRelList vrl,
|
VRelList vrl,
|
||||||
cur;
|
cur;
|
||||||
Datum d;
|
Datum d;
|
||||||
@ -276,7 +284,6 @@ getrels(NameData *VacRelP)
|
|||||||
F_CHAREQ, CharGetDatum('r'));
|
F_CHAREQ, CharGetDatum('r'));
|
||||||
}
|
}
|
||||||
|
|
||||||
portalmem = CommonSpecialPortalGetMemory();
|
|
||||||
vrl = cur = (VRelList) NULL;
|
vrl = cur = (VRelList) NULL;
|
||||||
|
|
||||||
rel = heap_openr(RelationRelationName, AccessShareLock);
|
rel = heap_openr(RelationRelationName, AccessShareLock);
|
||||||
@ -302,25 +309,26 @@ getrels(NameData *VacRelP)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* get a relation list entry for this guy */
|
/* get a relation list entry for this guy */
|
||||||
old = MemoryContextSwitchTo((MemoryContext) portalmem);
|
|
||||||
if (vrl == (VRelList) NULL)
|
if (vrl == (VRelList) NULL)
|
||||||
vrl = cur = (VRelList) palloc(sizeof(VRelListData));
|
vrl = cur = (VRelList)
|
||||||
|
MemoryContextAlloc(vac_context, sizeof(VRelListData));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
|
cur->vrl_next = (VRelList)
|
||||||
|
MemoryContextAlloc(vac_context, sizeof(VRelListData));
|
||||||
cur = cur->vrl_next;
|
cur = cur->vrl_next;
|
||||||
}
|
}
|
||||||
MemoryContextSwitchTo(old);
|
|
||||||
|
|
||||||
cur->vrl_relid = tuple->t_data->t_oid;
|
cur->vrl_relid = tuple->t_data->t_oid;
|
||||||
cur->vrl_next = (VRelList) NULL;
|
cur->vrl_next = (VRelList) NULL;
|
||||||
}
|
}
|
||||||
if (found == false)
|
|
||||||
elog(NOTICE, "Vacuum: table not found");
|
|
||||||
|
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(rel, AccessShareLock);
|
heap_close(rel, AccessShareLock);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
elog(NOTICE, "Vacuum: table not found");
|
||||||
|
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
|
|
||||||
return vrl;
|
return vrl;
|
||||||
@ -2275,62 +2283,6 @@ vac_cmp_vtlinks(const void *left, const void *right)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This routines handle a special cross-transaction portal.
|
|
||||||
* However it is automatically closed in case of abort.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
CommonSpecialPortalOpen(void)
|
|
||||||
{
|
|
||||||
char *pname;
|
|
||||||
|
|
||||||
|
|
||||||
if (CommonSpecialPortalInUse)
|
|
||||||
elog(ERROR, "CommonSpecialPortal is in use");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a portal for safe memory across transactions. We need to
|
|
||||||
* palloc the name space for it because our hash function expects the
|
|
||||||
* name to be on a longword boundary. CreatePortal copies the name to
|
|
||||||
* safe storage for us.
|
|
||||||
*/
|
|
||||||
pname = pstrdup(VACPNAME);
|
|
||||||
vac_portal = CreatePortal(pname);
|
|
||||||
pfree(pname);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set flag to indicate that vac_portal must be removed after an error.
|
|
||||||
* This global variable is checked in the transaction manager on xact
|
|
||||||
* abort, and the routine CommonSpecialPortalClose() is called if
|
|
||||||
* necessary.
|
|
||||||
*/
|
|
||||||
CommonSpecialPortalInUse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CommonSpecialPortalClose(void)
|
|
||||||
{
|
|
||||||
/* Clear flag first, to avoid recursion if PortalDrop elog's */
|
|
||||||
CommonSpecialPortalInUse = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Release our portal for cross-transaction memory.
|
|
||||||
*/
|
|
||||||
PortalDrop(&vac_portal);
|
|
||||||
}
|
|
||||||
|
|
||||||
PortalVariableMemory
|
|
||||||
CommonSpecialPortalGetMemory(void)
|
|
||||||
{
|
|
||||||
return PortalGetVariableMemory(vac_portal);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CommonSpecialPortalIsOpen(void)
|
|
||||||
{
|
|
||||||
return CommonSpecialPortalInUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_indices(Relation relation, int *nindices, Relation **Irel)
|
get_indices(Relation relation, int *nindices, Relation **Irel)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.34 2000/05/28 17:55:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.35 2000/06/28 03:31:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -87,8 +87,8 @@ init_execution_state(FunctionCachePtr fcache)
|
|||||||
nextes = newes;
|
nextes = newes;
|
||||||
preves = (execution_state *) NULL;
|
preves = (execution_state *) NULL;
|
||||||
|
|
||||||
queryTree_list = pg_parse_and_rewrite(fcache->src, fcache->argOidVect,
|
queryTree_list = pg_parse_and_rewrite(fcache->src,
|
||||||
nargs, FALSE);
|
fcache->argOidVect, nargs);
|
||||||
|
|
||||||
foreach(qtl_item, queryTree_list)
|
foreach(qtl_item, queryTree_list)
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.67 2000/06/15 03:32:09 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.68 2000/06/28 03:31:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -265,7 +265,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
|
|||||||
else
|
else
|
||||||
newVal = FunctionCallInvoke(&fcinfo);
|
newVal = FunctionCallInvoke(&fcinfo);
|
||||||
if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
|
if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
|
||||||
pfree(peraggstate->value1);
|
pfree(DatumGetPointer(peraggstate->value1));
|
||||||
peraggstate->value1 = newVal;
|
peraggstate->value1 = newVal;
|
||||||
peraggstate->value1IsNull = fcinfo.isnull;
|
peraggstate->value1IsNull = fcinfo.isnull;
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
|
|||||||
else
|
else
|
||||||
newVal = FunctionCallInvoke(&fcinfo);
|
newVal = FunctionCallInvoke(&fcinfo);
|
||||||
if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
|
if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
|
||||||
pfree(peraggstate->value2);
|
pfree(DatumGetPointer(peraggstate->value2));
|
||||||
peraggstate->value2 = newVal;
|
peraggstate->value2 = newVal;
|
||||||
peraggstate->value2IsNull = fcinfo.isnull;
|
peraggstate->value2IsNull = fcinfo.isnull;
|
||||||
}
|
}
|
||||||
@ -424,12 +424,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
|
|||||||
if (OidIsValid(peraggstate->xfn1_oid) &&
|
if (OidIsValid(peraggstate->xfn1_oid) &&
|
||||||
!peraggstate->value1IsNull &&
|
!peraggstate->value1IsNull &&
|
||||||
!peraggstate->transtype1ByVal)
|
!peraggstate->transtype1ByVal)
|
||||||
pfree(peraggstate->value1);
|
pfree(DatumGetPointer(peraggstate->value1));
|
||||||
|
|
||||||
if (OidIsValid(peraggstate->xfn2_oid) &&
|
if (OidIsValid(peraggstate->xfn2_oid) &&
|
||||||
!peraggstate->value2IsNull &&
|
!peraggstate->value2IsNull &&
|
||||||
!peraggstate->transtype2ByVal)
|
!peraggstate->transtype2ByVal)
|
||||||
pfree(peraggstate->value2);
|
pfree(DatumGetPointer(peraggstate->value2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------
|
/* ---------------------------------------
|
||||||
|
@ -7,14 +7,14 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $Id: nodeHash.c,v 1.47 2000/06/15 04:09:52 momjian Exp $
|
* $Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* ExecHash - generate an in-memory hash table of the relation
|
* ExecHash - generate an in-memory hash table of the relation
|
||||||
* ExecInitHash - initialize node and subnodes..
|
* ExecInitHash - initialize node and subnodes
|
||||||
* ExecEndHash - shutdown node and subnodes
|
* ExecEndHash - shutdown node and subnodes
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -23,11 +23,12 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "executor/execdebug.h"
|
#include "executor/execdebug.h"
|
||||||
#include "executor/nodeHash.h"
|
#include "executor/nodeHash.h"
|
||||||
#include "executor/nodeHashjoin.h"
|
#include "executor/nodeHashjoin.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "utils/portal.h"
|
|
||||||
|
|
||||||
static int hashFunc(Datum key, int len, bool byVal);
|
static int hashFunc(Datum key, int len, bool byVal);
|
||||||
|
|
||||||
@ -235,8 +236,6 @@ ExecHashTableCreate(Hash *node)
|
|||||||
int totalbuckets;
|
int totalbuckets;
|
||||||
int bucketsize;
|
int bucketsize;
|
||||||
int i;
|
int i;
|
||||||
Portal myPortal;
|
|
||||||
char myPortalName[64];
|
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -348,23 +347,21 @@ ExecHashTableCreate(Hash *node)
|
|||||||
hashtable->outerBatchSize = NULL;
|
hashtable->outerBatchSize = NULL;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Create a named portal in which to keep the hashtable working storage.
|
* Create temporary memory contexts in which to keep the hashtable
|
||||||
* Each hashjoin must have its own portal, so be wary of name conflicts.
|
* working storage. See notes in executor/hashjoin.h.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
i = 0;
|
hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
|
||||||
do
|
"HashTableContext",
|
||||||
{
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
i++;
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
sprintf(myPortalName, "<hashtable %d>", i);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
myPortal = GetPortalByName(myPortalName);
|
|
||||||
} while (PortalIsValid(myPortal));
|
hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
|
||||||
myPortal = CreatePortal(myPortalName);
|
"HashBatchContext",
|
||||||
Assert(PortalIsValid(myPortal));
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
hashtable->myPortal = (void *) myPortal; /* kluge for circular
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
* includes */
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
|
|
||||||
hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
|
|
||||||
|
|
||||||
/* Allocate data that will live for the life of the hashjoin */
|
/* Allocate data that will live for the life of the hashjoin */
|
||||||
|
|
||||||
@ -395,11 +392,10 @@ ExecHashTableCreate(Hash *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare portal for the first-scan space allocations; allocate the
|
* Prepare context for the first-scan space allocations; allocate the
|
||||||
* hashbucket array therein, and set each bucket "empty".
|
* hashbucket array therein, and set each bucket "empty".
|
||||||
*/
|
*/
|
||||||
MemoryContextSwitchTo(hashtable->batchCxt);
|
MemoryContextSwitchTo(hashtable->batchCxt);
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
|
||||||
|
|
||||||
hashtable->buckets = (HashJoinTuple *)
|
hashtable->buckets = (HashJoinTuple *)
|
||||||
palloc(nbuckets * sizeof(HashJoinTuple));
|
palloc(nbuckets * sizeof(HashJoinTuple));
|
||||||
@ -435,9 +431,8 @@ ExecHashTableDestroy(HashJoinTable hashtable)
|
|||||||
BufFileClose(hashtable->outerBatchFile[i]);
|
BufFileClose(hashtable->outerBatchFile[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy the portal to release all working memory */
|
/* Release working memory (batchCxt is a child, so it goes away too) */
|
||||||
/* cast here is a kluge for circular includes... */
|
MemoryContextDelete(hashtable->hashCxt);
|
||||||
PortalDrop((Portal *) &hashtable->myPortal);
|
|
||||||
|
|
||||||
/* And drop the control block */
|
/* And drop the control block */
|
||||||
pfree(hashtable);
|
pfree(hashtable);
|
||||||
@ -676,11 +671,10 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Release all the hash buckets and tuples acquired in the prior pass,
|
* Release all the hash buckets and tuples acquired in the prior pass,
|
||||||
* and reinitialize the portal for a new pass.
|
* and reinitialize the context for a new pass.
|
||||||
*/
|
*/
|
||||||
|
MemoryContextReset(hashtable->batchCxt);
|
||||||
oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
|
oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
|
||||||
EndPortalAllocMode();
|
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We still use the same number of physical buckets as in the first
|
* We still use the same number of physical buckets as in the first
|
||||||
|
@ -3,21 +3,20 @@
|
|||||||
* spi.c
|
* spi.c
|
||||||
* Server Programming Interface
|
* Server Programming Interface
|
||||||
*
|
*
|
||||||
* $Id: spi.c,v 1.46 2000/05/30 04:24:45 tgl Exp $
|
* $Id: spi.c,v 1.47 2000/06/28 03:31:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "executor/spi_priv.h"
|
#include "executor/spi_priv.h"
|
||||||
#include "access/printtup.h"
|
#include "access/printtup.h"
|
||||||
|
|
||||||
static Portal _SPI_portal = (Portal) NULL;
|
|
||||||
static _SPI_connection *_SPI_stack = NULL;
|
static _SPI_connection *_SPI_stack = NULL;
|
||||||
static _SPI_connection *_SPI_current = NULL;
|
static _SPI_connection *_SPI_current = NULL;
|
||||||
static int _SPI_connected = -1;
|
static int _SPI_connected = -1;
|
||||||
static int _SPI_curid = -1;
|
static int _SPI_curid = -1;
|
||||||
|
|
||||||
DLLIMPORT uint32 SPI_processed = 0;
|
DLLIMPORT uint32 SPI_processed = 0;
|
||||||
DLLIMPORT SPITupleTable *SPI_tuptable;
|
DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
|
||||||
DLLIMPORT int SPI_result;
|
DLLIMPORT int SPI_result;
|
||||||
|
|
||||||
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
||||||
@ -46,28 +45,6 @@ extern void ShowUsage(void);
|
|||||||
int
|
int
|
||||||
SPI_connect()
|
SPI_connect()
|
||||||
{
|
{
|
||||||
char pname[64];
|
|
||||||
PortalVariableMemory pvmem;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* It's possible on startup and after commit/abort. In future we'll
|
|
||||||
* catch commit/abort in some way...
|
|
||||||
*/
|
|
||||||
strcpy(pname, "<SPI manager>");
|
|
||||||
_SPI_portal = GetPortalByName(pname);
|
|
||||||
if (!PortalIsValid(_SPI_portal))
|
|
||||||
{
|
|
||||||
if (_SPI_stack != NULL) /* there was abort */
|
|
||||||
free(_SPI_stack);
|
|
||||||
_SPI_current = _SPI_stack = NULL;
|
|
||||||
_SPI_connected = _SPI_curid = -1;
|
|
||||||
SPI_processed = 0;
|
|
||||||
SPI_tuptable = NULL;
|
|
||||||
_SPI_portal = CreatePortal(pname);
|
|
||||||
if (!PortalIsValid(_SPI_portal))
|
|
||||||
elog(FATAL, "SPI_connect: global initialization failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When procedure called by Executor _SPI_curid expected to be equal
|
* When procedure called by Executor _SPI_curid expected to be equal
|
||||||
* to _SPI_connected
|
* to _SPI_connected
|
||||||
@ -99,15 +76,19 @@ SPI_connect()
|
|||||||
_SPI_current->processed = 0;
|
_SPI_current->processed = 0;
|
||||||
_SPI_current->tuptable = NULL;
|
_SPI_current->tuptable = NULL;
|
||||||
|
|
||||||
/* Create Portal for this procedure ... */
|
/* Create memory contexts for this procedure */
|
||||||
snprintf(pname, 64, "<SPI %d>", _SPI_connected);
|
_SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
|
||||||
_SPI_current->portal = CreatePortal(pname);
|
"SPI Proc",
|
||||||
if (!PortalIsValid(_SPI_current->portal))
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
elog(FATAL, "SPI_connect: initialization failed");
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
/* ... and switch to Portal' Variable memory - procedure' context */
|
_SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
|
||||||
pvmem = PortalGetVariableMemory(_SPI_current->portal);
|
"SPI Exec",
|
||||||
_SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
/* ... and switch to procedure's context */
|
||||||
|
_SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
|
||||||
|
|
||||||
_SPI_current->savedId = GetScanCommandId();
|
_SPI_current->savedId = GetScanCommandId();
|
||||||
SetScanCommandId(GetCurrentCommandId());
|
SetScanCommandId(GetCurrentCommandId());
|
||||||
@ -127,7 +108,10 @@ SPI_finish()
|
|||||||
|
|
||||||
/* Restore memory context as it was before procedure call */
|
/* Restore memory context as it was before procedure call */
|
||||||
MemoryContextSwitchTo(_SPI_current->savedcxt);
|
MemoryContextSwitchTo(_SPI_current->savedcxt);
|
||||||
PortalDrop(&(_SPI_current->portal));
|
|
||||||
|
/* Release memory used in procedure call */
|
||||||
|
MemoryContextDelete(_SPI_current->execCxt);
|
||||||
|
MemoryContextDelete(_SPI_current->procCxt);
|
||||||
|
|
||||||
SetScanCommandId(_SPI_current->savedId);
|
SetScanCommandId(_SPI_current->savedId);
|
||||||
|
|
||||||
@ -142,6 +126,7 @@ SPI_finish()
|
|||||||
{
|
{
|
||||||
free(_SPI_stack);
|
free(_SPI_stack);
|
||||||
_SPI_stack = NULL;
|
_SPI_stack = NULL;
|
||||||
|
_SPI_current = NULL;
|
||||||
}
|
}
|
||||||
else
|
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
|
void
|
||||||
SPI_push(void)
|
SPI_push(void)
|
||||||
{
|
{
|
||||||
@ -508,61 +512,22 @@ SPI_palloc(Size size)
|
|||||||
void *
|
void *
|
||||||
SPI_repalloc(void *pointer, Size size)
|
SPI_repalloc(void *pointer, Size size)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt = NULL;
|
/* No longer need to worry which context chunk was in... */
|
||||||
|
return repalloc(pointer, size);
|
||||||
if (_SPI_curid + 1 == _SPI_connected) /* connected */
|
|
||||||
{
|
|
||||||
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
|
|
||||||
elog(FATAL, "SPI: stack corrupted");
|
|
||||||
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer = repalloc(pointer, size);
|
|
||||||
|
|
||||||
if (oldcxt)
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
return pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SPI_pfree(void *pointer)
|
SPI_pfree(void *pointer)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt = NULL;
|
/* No longer need to worry which context chunk was in... */
|
||||||
|
|
||||||
if (_SPI_curid + 1 == _SPI_connected) /* connected */
|
|
||||||
{
|
|
||||||
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
|
|
||||||
elog(FATAL, "SPI: stack corrupted");
|
|
||||||
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
|
|
||||||
}
|
|
||||||
|
|
||||||
pfree(pointer);
|
pfree(pointer);
|
||||||
|
|
||||||
if (oldcxt)
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SPI_freetuple(HeapTuple tuple)
|
SPI_freetuple(HeapTuple tuple)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt = NULL;
|
/* No longer need to worry which context tuple was in... */
|
||||||
|
|
||||||
if (_SPI_curid + 1 == _SPI_connected) /* connected */
|
|
||||||
{
|
|
||||||
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
|
|
||||||
elog(FATAL, "SPI: stack corrupted");
|
|
||||||
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
|
|
||||||
}
|
|
||||||
|
|
||||||
heap_freetuple(tuple);
|
heap_freetuple(tuple);
|
||||||
|
|
||||||
if (oldcxt)
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =================== private functions =================== */
|
/* =================== private functions =================== */
|
||||||
@ -647,7 +612,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
|||||||
argtypes = plan->argtypes;
|
argtypes = plan->argtypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs, FALSE);
|
queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
|
||||||
|
|
||||||
_SPI_current->qtlist = queryTree_list;
|
_SPI_current->qtlist = queryTree_list;
|
||||||
|
|
||||||
@ -790,7 +755,6 @@ static int
|
|||||||
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||||
{
|
{
|
||||||
Query *parseTree = queryDesc->parsetree;
|
Query *parseTree = queryDesc->parsetree;
|
||||||
Plan *plan = queryDesc->plantree;
|
|
||||||
int operation = queryDesc->operation;
|
int operation = queryDesc->operation;
|
||||||
CommandDest dest = queryDesc->dest;
|
CommandDest dest = queryDesc->dest;
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
@ -875,16 +839,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
#endif
|
#endif
|
||||||
tupdesc = ExecutorStart(queryDesc, state);
|
tupdesc = ExecutorStart(queryDesc, state);
|
||||||
|
|
||||||
/* Don't work currently */
|
/* Don't work currently --- need to rearrange callers so that
|
||||||
|
* we prepare the portal before doing CreateExecutorState() etc.
|
||||||
|
* See pquery.c for the correct order of operations.
|
||||||
|
*/
|
||||||
if (isRetrieveIntoPortal)
|
if (isRetrieveIntoPortal)
|
||||||
{
|
{
|
||||||
ProcessPortal(intoName,
|
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
||||||
parseTree,
|
|
||||||
plan,
|
|
||||||
state,
|
|
||||||
tupdesc,
|
|
||||||
None);
|
|
||||||
return SPI_OK_CURSOR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
|
ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
|
||||||
@ -920,27 +881,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
static MemoryContext
|
static MemoryContext
|
||||||
_SPI_execmem()
|
_SPI_execmem()
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
return MemoryContextSwitchTo(_SPI_current->execCxt);
|
||||||
PortalHeapMemory phmem;
|
|
||||||
|
|
||||||
phmem = PortalGetHeapMemory(_SPI_current->portal);
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
|
|
||||||
|
|
||||||
return oldcxt;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryContext
|
static MemoryContext
|
||||||
_SPI_procmem()
|
_SPI_procmem()
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
return MemoryContextSwitchTo(_SPI_current->procCxt);
|
||||||
PortalVariableMemory pvmem;
|
|
||||||
|
|
||||||
pvmem = PortalGetVariableMemory(_SPI_current->portal);
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
|
|
||||||
|
|
||||||
return oldcxt;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -959,7 +906,6 @@ _SPI_begin_call(bool execmem)
|
|||||||
if (execmem) /* switch to the Executor memory context */
|
if (execmem) /* switch to the Executor memory context */
|
||||||
{
|
{
|
||||||
_SPI_execmem();
|
_SPI_execmem();
|
||||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -977,9 +923,10 @@ _SPI_end_call(bool procmem)
|
|||||||
_SPI_current->qtlist = NULL;
|
_SPI_current->qtlist = NULL;
|
||||||
|
|
||||||
if (procmem) /* switch to the procedure memory context */
|
if (procmem) /* switch to the procedure memory context */
|
||||||
{ /* but free Executor memory before */
|
{
|
||||||
EndPortalAllocMode();
|
|
||||||
_SPI_procmem();
|
_SPI_procmem();
|
||||||
|
/* and free Executor memory */
|
||||||
|
MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1016,8 +963,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
|
|||||||
MemoryContext oldcxt = NULL;
|
MemoryContext oldcxt = NULL;
|
||||||
|
|
||||||
if (location == _SPI_CPLAN_PROCXT)
|
if (location == _SPI_CPLAN_PROCXT)
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext)
|
oldcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
|
||||||
PortalGetVariableMemory(_SPI_current->portal));
|
|
||||||
else if (location == _SPI_CPLAN_TOPCXT)
|
else if (location == _SPI_CPLAN_TOPCXT)
|
||||||
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
|
||||||
@ -1033,7 +979,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
|
|||||||
else
|
else
|
||||||
newplan->argtypes = NULL;
|
newplan->argtypes = NULL;
|
||||||
|
|
||||||
if (location != _SPI_CPLAN_CURCXT)
|
if (oldcxt != NULL)
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
return newplan;
|
return newplan;
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
# Makefile for lib (miscellaneous stuff)
|
# Makefile for lib (miscellaneous stuff)
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.13 2000/05/29 05:44:45 tgl Exp $
|
# $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.14 2000/06/28 03:31:34 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
SRCDIR = ../..
|
SRCDIR = ../..
|
||||||
include ../../Makefile.global
|
include ../../Makefile.global
|
||||||
|
|
||||||
OBJS = bit.o fstack.o hasht.o lispsort.o stringinfo.o dllist.o
|
OBJS = bit.o hasht.o lispsort.o stringinfo.o dllist.o
|
||||||
|
|
||||||
all: SUBSYS.o
|
all: SUBSYS.o
|
||||||
|
|
||||||
|
@ -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) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: stringinfo.c,v 1.25 2000/04/12 17:15:11 momjian Exp $
|
* $Id: stringinfo.c,v 1.26 2000/06/28 03:31:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,8 +29,6 @@ makeStringInfo(void)
|
|||||||
StringInfo res;
|
StringInfo res;
|
||||||
|
|
||||||
res = (StringInfo) palloc(sizeof(StringInfoData));
|
res = (StringInfo) palloc(sizeof(StringInfoData));
|
||||||
if (res == NULL)
|
|
||||||
elog(ERROR, "makeStringInfo: Out of memory");
|
|
||||||
|
|
||||||
initStringInfo(res);
|
initStringInfo(res);
|
||||||
|
|
||||||
@ -49,9 +47,6 @@ initStringInfo(StringInfo str)
|
|||||||
int size = 256; /* initial default buffer size */
|
int size = 256; /* initial default buffer size */
|
||||||
|
|
||||||
str->data = (char *) palloc(size);
|
str->data = (char *) palloc(size);
|
||||||
if (str->data == NULL)
|
|
||||||
elog(ERROR,
|
|
||||||
"initStringInfo: Out of memory (%d bytes requested)", size);
|
|
||||||
str->maxlen = size;
|
str->maxlen = size;
|
||||||
str->len = 0;
|
str->len = 0;
|
||||||
str->data[0] = '\0';
|
str->data[0] = '\0';
|
||||||
@ -62,6 +57,11 @@ initStringInfo(StringInfo str)
|
|||||||
*
|
*
|
||||||
* Internal routine: make sure there is enough space for 'needed' more bytes
|
* Internal routine: make sure there is enough space for 'needed' more bytes
|
||||||
* ('needed' does not include the terminating null).
|
* ('needed' does not include the terminating null).
|
||||||
|
*
|
||||||
|
* NB: because we use repalloc() to enlarge the buffer, the string buffer
|
||||||
|
* will remain allocated in the same memory context that was current when
|
||||||
|
* initStringInfo was called, even if another context is now current.
|
||||||
|
* This is the desired and indeed critical behavior!
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
enlargeStringInfo(StringInfo str, int needed)
|
enlargeStringInfo(StringInfo str, int needed)
|
||||||
@ -83,9 +83,6 @@ enlargeStringInfo(StringInfo str, int needed)
|
|||||||
newlen = 2 * newlen;
|
newlen = 2 * newlen;
|
||||||
|
|
||||||
str->data = (char *) repalloc(str->data, newlen);
|
str->data = (char *) repalloc(str->data, newlen);
|
||||||
if (str->data == NULL)
|
|
||||||
elog(ERROR,
|
|
||||||
"enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
|
|
||||||
|
|
||||||
str->maxlen = newlen;
|
str->maxlen = newlen;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.46 2000/06/09 01:11:06 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.47 2000/06/28 03:31:41 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This should be moved to a more appropriate place. It is here
|
* This should be moved to a more appropriate place. It is here
|
||||||
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
* Builtin functions for open/close/read/write operations on large objects.
|
* Builtin functions for open/close/read/write operations on large objects.
|
||||||
*
|
*
|
||||||
* These functions operate in a private GlobalMemoryContext, which means
|
* These functions operate in a private MemoryContext, which means
|
||||||
* that large object descriptors hang around until we destroy the context.
|
* that large object descriptors hang around until we destroy the context.
|
||||||
* That happens in lo_commit(). It'd be possible to prolong the lifetime
|
* That happens in lo_commit(). It'd be possible to prolong the lifetime
|
||||||
* of the context so that LO FDs are good across transactions (for example,
|
* of the context so that LO FDs are good across transactions (for example,
|
||||||
@ -24,8 +24,10 @@
|
|||||||
* But we'd need additional state in order to do the right thing at the
|
* But we'd need additional state in order to do the right thing at the
|
||||||
* end of an aborted transaction. FDs opened during an aborted xact would
|
* end of an aborted transaction. FDs opened during an aborted xact would
|
||||||
* still need to be closed, since they might not be pointing at valid
|
* still need to be closed, since they might not be pointing at valid
|
||||||
* relations at all. For now, we'll stick with the existing documented
|
* relations at all. Locking semantics are also an interesting problem
|
||||||
* semantics of LO FDs: they're only good within a transaction.
|
* if LOs stay open across transactions. For now, we'll stick with the
|
||||||
|
* existing documented semantics of LO FDs: they're only good within a
|
||||||
|
* transaction.
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -56,7 +58,7 @@
|
|||||||
*/
|
*/
|
||||||
static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
|
static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
|
||||||
|
|
||||||
static GlobalMemory fscxt = NULL;
|
static MemoryContext fscxt = NULL;
|
||||||
|
|
||||||
|
|
||||||
static int newLOfd(LargeObjectDesc *lobjCookie);
|
static int newLOfd(LargeObjectDesc *lobjCookie);
|
||||||
@ -80,8 +82,13 @@ lo_open(PG_FUNCTION_ARGS)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fscxt == NULL)
|
if (fscxt == NULL)
|
||||||
fscxt = CreateGlobalMemory("Filesystem");
|
fscxt = AllocSetContextCreate(TopMemoryContext,
|
||||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
"Filesystem",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
|
currentContext = MemoryContextSwitchTo(fscxt);
|
||||||
|
|
||||||
lobjDesc = inv_open(lobjId, mode);
|
lobjDesc = inv_open(lobjId, mode);
|
||||||
|
|
||||||
@ -128,7 +135,7 @@ lo_close(PG_FUNCTION_ARGS)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
Assert(fscxt != NULL);
|
Assert(fscxt != NULL);
|
||||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
currentContext = MemoryContextSwitchTo(fscxt);
|
||||||
|
|
||||||
inv_close(cookies[fd]);
|
inv_close(cookies[fd]);
|
||||||
|
|
||||||
@ -166,7 +173,7 @@ lo_read(int fd, char *buf, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Assert(fscxt != NULL);
|
Assert(fscxt != NULL);
|
||||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
currentContext = MemoryContextSwitchTo(fscxt);
|
||||||
|
|
||||||
status = inv_read(cookies[fd], buf, len);
|
status = inv_read(cookies[fd], buf, len);
|
||||||
|
|
||||||
@ -193,7 +200,7 @@ lo_write(int fd, char *buf, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Assert(fscxt != NULL);
|
Assert(fscxt != NULL);
|
||||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
currentContext = MemoryContextSwitchTo(fscxt);
|
||||||
|
|
||||||
status = inv_write(cookies[fd], buf, len);
|
status = inv_write(cookies[fd], buf, len);
|
||||||
|
|
||||||
@ -224,7 +231,7 @@ lo_lseek(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Assert(fscxt != NULL);
|
Assert(fscxt != NULL);
|
||||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
currentContext = MemoryContextSwitchTo(fscxt);
|
||||||
|
|
||||||
status = inv_seek(cookies[fd], offset, whence);
|
status = inv_seek(cookies[fd], offset, whence);
|
||||||
|
|
||||||
@ -242,9 +249,13 @@ lo_creat(PG_FUNCTION_ARGS)
|
|||||||
Oid lobjId;
|
Oid lobjId;
|
||||||
|
|
||||||
if (fscxt == NULL)
|
if (fscxt == NULL)
|
||||||
fscxt = CreateGlobalMemory("Filesystem");
|
fscxt = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"Filesystem",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
currentContext = MemoryContextSwitchTo(fscxt);
|
||||||
|
|
||||||
lobjDesc = inv_create(mode);
|
lobjDesc = inv_create(mode);
|
||||||
|
|
||||||
@ -493,7 +504,7 @@ lo_commit(bool isCommit)
|
|||||||
if (fscxt == NULL)
|
if (fscxt == NULL)
|
||||||
return; /* no LO operations in this xact */
|
return; /* no LO operations in this xact */
|
||||||
|
|
||||||
currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
|
currentContext = MemoryContextSwitchTo(fscxt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean out still-open index scans (not necessary if aborting) and
|
* Clean out still-open index scans (not necessary if aborting) and
|
||||||
@ -512,7 +523,7 @@ lo_commit(bool isCommit)
|
|||||||
MemoryContextSwitchTo(currentContext);
|
MemoryContextSwitchTo(currentContext);
|
||||||
|
|
||||||
/* Release the LO memory context to prevent permanent memory leaks. */
|
/* Release the LO memory context to prevent permanent memory leaks. */
|
||||||
GlobalMemoryDestroy(fscxt);
|
MemoryContextDelete(fscxt);
|
||||||
fscxt = NULL;
|
fscxt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.32 2000/05/28 17:55:56 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.33 2000/06/28 03:31:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -135,9 +135,11 @@ PQexec(char *query)
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* pg_exec_query_dest will put the query results in a portal which will
|
* pg_exec_query_dest will put the query results in a portal which will
|
||||||
* end up on the top of the portal stack.
|
* end up on the top of the portal stack.
|
||||||
|
*
|
||||||
|
* XXX memory context manipulation needs thought here.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
pg_exec_query_dest(query, Local, FALSE);
|
pg_exec_query_dest(query, Local, CurrentMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* pop the portal off the portal stack and return the
|
* pop the portal off the portal stack and return the
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.15 2000/06/11 11:39:50 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.16 2000/06/28 03:31:41 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This shouldn't be in libpq, but the monitor and some other
|
* This shouldn't be in libpq, but the monitor and some other
|
||||||
@ -44,6 +44,44 @@
|
|||||||
|
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize BlockSig and UnBlockSig.
|
||||||
|
*
|
||||||
|
* BlockSig is the set of signals to block when we are trying to block
|
||||||
|
* signals. This includes all signals we normally expect to get, but NOT
|
||||||
|
* signals that should never be turned off.
|
||||||
|
*
|
||||||
|
* UnBlockSig is the set of signals to block when we don't want to block
|
||||||
|
* signals (is this ever nonzero??)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pqinitmask(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SIGPROCMASK
|
||||||
|
sigemptyset(&UnBlockSig);
|
||||||
|
sigfillset(&BlockSig);
|
||||||
|
sigdelset(&BlockSig, SIGABRT);
|
||||||
|
sigdelset(&BlockSig, SIGILL);
|
||||||
|
sigdelset(&BlockSig, SIGSEGV);
|
||||||
|
sigdelset(&BlockSig, SIGBUS);
|
||||||
|
sigdelset(&BlockSig, SIGTRAP);
|
||||||
|
sigdelset(&BlockSig, SIGCONT);
|
||||||
|
sigdelset(&BlockSig, SIGSYS);
|
||||||
|
#else
|
||||||
|
UnBlockSig = 0;
|
||||||
|
BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) |
|
||||||
|
sigmask(SIGTERM) | sigmask(SIGALRM) |
|
||||||
|
sigmask(SIGINT) | sigmask(SIGUSR1) |
|
||||||
|
sigmask(SIGUSR2) | sigmask(SIGCHLD) |
|
||||||
|
sigmask(SIGWINCH) | sigmask(SIGFPE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up a signal handler
|
||||||
|
*/
|
||||||
pqsigfunc
|
pqsigfunc
|
||||||
pqsignal(int signo, pqsigfunc func)
|
pqsignal(int signo, pqsigfunc func)
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: geqo_eval.c,v 1.50 2000/05/30 00:49:46 momjian Exp $
|
* $Id: geqo_eval.c,v 1.51 2000/06/28 03:31:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,9 +19,9 @@
|
|||||||
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#ifdef HAVE_LIMITS_H
|
#ifdef HAVE_LIMITS_H
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#else
|
#else
|
||||||
@ -33,42 +33,9 @@
|
|||||||
#include "optimizer/geqo.h"
|
#include "optimizer/geqo.h"
|
||||||
#include "optimizer/pathnode.h"
|
#include "optimizer/pathnode.h"
|
||||||
#include "optimizer/paths.h"
|
#include "optimizer/paths.h"
|
||||||
#include "utils/portal.h"
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Variables set by geqo_eval_startup for use within a single GEQO run
|
|
||||||
*/
|
|
||||||
static MemoryContext geqo_eval_context;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* geqo_eval_startup:
|
|
||||||
* Must be called during geqo_main startup (before geqo_eval may be called)
|
|
||||||
*
|
|
||||||
* The main thing we need to do here is prepare a private memory context for
|
|
||||||
* allocation of temp storage used while constructing a path in geqo_eval().
|
|
||||||
* Since geqo_eval() will be called many times, we can't afford to let all
|
|
||||||
* that memory go unreclaimed until end of statement. We use a special
|
|
||||||
* named portal to hold the context, so that it will be freed even if
|
|
||||||
* we abort via elog(ERROR). The working data is allocated in the portal's
|
|
||||||
* heap memory context.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
geqo_eval_startup(void)
|
|
||||||
{
|
|
||||||
#define GEQO_PORTAL_NAME "<geqo workspace>"
|
|
||||||
Portal geqo_portal = GetPortalByName(GEQO_PORTAL_NAME);
|
|
||||||
|
|
||||||
if (!PortalIsValid(geqo_portal))
|
|
||||||
{
|
|
||||||
/* First time through (within current transaction, that is) */
|
|
||||||
geqo_portal = CreatePortal(GEQO_PORTAL_NAME);
|
|
||||||
Assert(PortalIsValid(geqo_portal));
|
|
||||||
}
|
|
||||||
|
|
||||||
geqo_eval_context = (MemoryContext) PortalGetHeapMemory(geqo_portal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* geqo_eval
|
* geqo_eval
|
||||||
*
|
*
|
||||||
@ -77,21 +44,31 @@ geqo_eval_startup(void)
|
|||||||
Cost
|
Cost
|
||||||
geqo_eval(Query *root, Gene *tour, int num_gene)
|
geqo_eval(Query *root, Gene *tour, int num_gene)
|
||||||
{
|
{
|
||||||
|
MemoryContext mycontext;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
RelOptInfo *joinrel;
|
RelOptInfo *joinrel;
|
||||||
Cost fitness;
|
Cost fitness;
|
||||||
List *savelist;
|
List *savelist;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 */
|
/* preserve root->join_rel_list, which gimme_tree changes */
|
||||||
savelist = root->join_rel_list;
|
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 */
|
/* construct the best path for the given combination of relations */
|
||||||
joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
|
joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
|
||||||
|
|
||||||
@ -107,8 +84,8 @@ geqo_eval(Query *root, Gene *tour, int num_gene)
|
|||||||
root->join_rel_list = savelist;
|
root->join_rel_list = savelist;
|
||||||
|
|
||||||
/* release all the memory acquired within gimme_tree */
|
/* release all the memory acquired within gimme_tree */
|
||||||
EndPortalAllocMode();
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
MemoryContextDelete(mycontext);
|
||||||
|
|
||||||
return fitness;
|
return fitness;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: geqo_main.c,v 1.21 2000/05/31 00:28:19 petere Exp $
|
* $Id: geqo_main.c,v 1.22 2000/06/28 03:31:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -110,9 +110,6 @@ geqo(Query *root)
|
|||||||
else
|
else
|
||||||
srandom(time(NULL));
|
srandom(time(NULL));
|
||||||
|
|
||||||
/* initialize plan evaluator */
|
|
||||||
geqo_eval_startup();
|
|
||||||
|
|
||||||
/* allocate genetic pool memory */
|
/* allocate genetic pool memory */
|
||||||
pool = alloc_pool(pool_size, number_of_rels);
|
pool = alloc_pool(pool_size, number_of_rels);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.149 2000/06/22 22:31:20 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.150 2000/06/28 03:31:52 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
@ -378,15 +378,38 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
umask((mode_t) 0077);
|
umask((mode_t) 0077);
|
||||||
|
|
||||||
ResetAllOptions();
|
|
||||||
|
|
||||||
MyProcPid = getpid();
|
MyProcPid = getpid();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fire up essential subsystems: error and memory management
|
||||||
|
*/
|
||||||
|
EnableExceptionHandling(true);
|
||||||
|
MemoryContextInit();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* By default, palloc() requests in the postmaster will be allocated
|
||||||
|
* in the PostmasterContext, which is space that can be recycled by
|
||||||
|
* backends. Allocated data that needs to be available to backends
|
||||||
|
* should be allocated in TopMemoryContext.
|
||||||
|
*/
|
||||||
|
PostmasterContext = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"Postmaster",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
MemoryContextSwitchTo(PostmasterContext);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Options setup
|
||||||
|
*/
|
||||||
if (getenv("PGDATA"))
|
if (getenv("PGDATA"))
|
||||||
DataDir = strdup(getenv("PGDATA")); /* default value */
|
DataDir = strdup(getenv("PGDATA")); /* default value */
|
||||||
|
|
||||||
if (getenv("PGPORT"))
|
if (getenv("PGPORT"))
|
||||||
PostPortName = atoi(getenv("PGPORT"));
|
PostPortName = atoi(getenv("PGPORT"));
|
||||||
|
|
||||||
|
ResetAllOptions();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First we must scan for a -D argument to get the data dir. Then
|
* First we must scan for a -D argument to get the data dir. Then
|
||||||
* read the config file. Finally, scan all the other arguments.
|
* read the config file. Finally, scan all the other arguments.
|
||||||
@ -600,7 +623,6 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* set up shared memory and semaphores */
|
/* set up shared memory and semaphores */
|
||||||
EnableMemoryContext(TRUE);
|
|
||||||
reset_shared(PostPortName);
|
reset_shared(PostPortName);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -662,7 +684,7 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Set up signal handlers for the postmaster process.
|
* Set up signal handlers for the postmaster process.
|
||||||
*/
|
*/
|
||||||
PG_INITMASK();
|
pqinitmask();
|
||||||
PG_SETMASK(&BlockSig);
|
PG_SETMASK(&BlockSig);
|
||||||
|
|
||||||
pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have children do same */
|
pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have children do same */
|
||||||
@ -1867,6 +1889,7 @@ DoBackend(Port *port)
|
|||||||
/* Save port etc. for ps status */
|
/* Save port etc. for ps status */
|
||||||
MyProcPort = port;
|
MyProcPort = port;
|
||||||
|
|
||||||
|
/* Reset MyProcPid to new backend's pid */
|
||||||
MyProcPid = getpid();
|
MyProcPid = getpid();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1946,6 +1969,19 @@ DoBackend(Port *port)
|
|||||||
|
|
||||||
av[ac] = (char *) NULL;
|
av[ac] = (char *) NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release postmaster's working memory context so that backend can
|
||||||
|
* recycle the space. Note we couldn't do it earlier than here,
|
||||||
|
* because port pointer is pointing into that space! But now we
|
||||||
|
* have copied all the interesting info into safe local storage.
|
||||||
|
*/
|
||||||
|
MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
MemoryContextDelete(PostmasterContext);
|
||||||
|
PostmasterContext = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug: print arguments being passed to backend
|
||||||
|
*/
|
||||||
if (DebugLvl > 1)
|
if (DebugLvl > 1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s child[%d]: starting with (",
|
fprintf(stderr, "%s child[%d]: starting with (",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.46 2000/06/15 04:09:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.47 2000/06/28 03:31:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -16,51 +16,20 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "catalog/catname.h"
|
||||||
|
#include "catalog/indexing.h"
|
||||||
|
#include "catalog/pg_rewrite.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
#include "rewrite/rewriteDefine.h"
|
#include "rewrite/rewriteDefine.h"
|
||||||
#include "rewrite/rewriteSupport.h"
|
#include "rewrite/rewriteSupport.h"
|
||||||
#include "tcop/tcopprot.h"
|
|
||||||
|
|
||||||
Oid LastOidProcessed = InvalidOid;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert given string to a suitably quoted string constant,
|
|
||||||
* and append it to the StringInfo buffer.
|
|
||||||
* XXX Any MULTIBYTE considerations here?
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
quoteString(StringInfo buf, char *source)
|
|
||||||
{
|
|
||||||
char *current;
|
|
||||||
|
|
||||||
appendStringInfoChar(buf, '\'');
|
|
||||||
for (current = source; *current; current++)
|
|
||||||
{
|
|
||||||
char ch = *current;
|
|
||||||
|
|
||||||
if (ch == '\'' || ch == '\\')
|
|
||||||
{
|
|
||||||
appendStringInfoChar(buf, '\\');
|
|
||||||
appendStringInfoChar(buf, ch);
|
|
||||||
}
|
|
||||||
else if (ch >= 0 && ch < ' ')
|
|
||||||
appendStringInfo(buf, "\\%03o", (int) ch);
|
|
||||||
else
|
|
||||||
appendStringInfoChar(buf, ch);
|
|
||||||
}
|
|
||||||
appendStringInfoChar(buf, '\'');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* InsertRule -
|
* InsertRule -
|
||||||
* takes the arguments and inserts them as attributes into the system
|
* takes the arguments and inserts them as attributes into the system
|
||||||
* relation "pg_rewrite"
|
* relation "pg_rewrite"
|
||||||
*
|
*
|
||||||
* MODS : changes the value of LastOidProcessed as a side
|
|
||||||
* effect of inserting the rule tuple
|
|
||||||
*
|
|
||||||
* ARGS : rulname - name of the rule
|
* ARGS : rulname - name of the rule
|
||||||
* evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
|
* evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
|
||||||
* evobj - name of relation
|
* evobj - name of relation
|
||||||
@ -78,11 +47,17 @@ InsertRule(char *rulname,
|
|||||||
bool evinstead,
|
bool evinstead,
|
||||||
char *actiontree)
|
char *actiontree)
|
||||||
{
|
{
|
||||||
StringInfoData rulebuf;
|
|
||||||
Relation eventrel;
|
Relation eventrel;
|
||||||
Oid eventrel_oid;
|
Oid eventrel_oid;
|
||||||
AttrNumber evslot_index;
|
AttrNumber evslot_index;
|
||||||
char *is_instead = "f";
|
int i;
|
||||||
|
Datum values[Natts_pg_rewrite];
|
||||||
|
char nulls[Natts_pg_rewrite];
|
||||||
|
NameData rname;
|
||||||
|
Relation pg_rewrite_desc;
|
||||||
|
TupleDesc tupDesc;
|
||||||
|
HeapTuple tup;
|
||||||
|
Oid rewriteObjectId;
|
||||||
|
|
||||||
eventrel = heap_openr(evobj, AccessShareLock);
|
eventrel = heap_openr(evobj, AccessShareLock);
|
||||||
eventrel_oid = RelationGetRelid(eventrel);
|
eventrel_oid = RelationGetRelid(eventrel);
|
||||||
@ -96,9 +71,6 @@ InsertRule(char *rulname,
|
|||||||
evslot_index = attnameAttNum(eventrel, evslot);
|
evslot_index = attnameAttNum(eventrel, evslot);
|
||||||
heap_close(eventrel, AccessShareLock);
|
heap_close(eventrel, AccessShareLock);
|
||||||
|
|
||||||
if (evinstead)
|
|
||||||
is_instead = "t";
|
|
||||||
|
|
||||||
if (evqual == NULL)
|
if (evqual == NULL)
|
||||||
evqual = "<>";
|
evqual = "<>";
|
||||||
|
|
||||||
@ -106,23 +78,54 @@ InsertRule(char *rulname,
|
|||||||
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
|
elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
|
||||||
rulname);
|
rulname);
|
||||||
|
|
||||||
initStringInfo(&rulebuf);
|
/* ----------------
|
||||||
appendStringInfo(&rulebuf,
|
* Set up *nulls and *values arrays
|
||||||
"INSERT INTO pg_rewrite (rulename, ev_type, ev_class, ev_attr, ev_action, ev_qual, is_instead) VALUES (");
|
* ----------------
|
||||||
quoteString(&rulebuf, rulname);
|
*/
|
||||||
appendStringInfo(&rulebuf, ", %d::char, %u::oid, %d::int2, ",
|
MemSet(nulls, ' ', sizeof(nulls));
|
||||||
evtype, eventrel_oid, evslot_index);
|
|
||||||
quoteString(&rulebuf, actiontree);
|
|
||||||
appendStringInfo(&rulebuf, "::text, ");
|
|
||||||
quoteString(&rulebuf, evqual);
|
|
||||||
appendStringInfo(&rulebuf, "::text, '%s'::bool);",
|
|
||||||
is_instead);
|
|
||||||
|
|
||||||
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
|
* 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
|
* create an in memory RewriteRule data structure which is cached by
|
||||||
* every Relation descriptor. (see utils/cache/relcache.c)
|
* every Relation descriptor. (see utils/cache/relcache.c)
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
|
thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
|
||||||
if (qual != NULL)
|
if (qual != NULL)
|
||||||
qual = copyObject(qual);
|
qual = copyObject(qual);
|
||||||
@ -159,7 +159,7 @@ prs2_addToRelation(Oid relid,
|
|||||||
if (relation->rd_rules == NULL)
|
if (relation->rd_rules == NULL)
|
||||||
{
|
{
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
rulelock = (RuleLock *) palloc(sizeof(RuleLock));
|
rulelock = (RuleLock *) palloc(sizeof(RuleLock));
|
||||||
rulelock->numLocks = 1;
|
rulelock->numLocks = 1;
|
||||||
rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
|
rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
|
||||||
@ -181,7 +181,7 @@ prs2_addToRelation(Oid relid,
|
|||||||
rulelock = relation->rd_rules;
|
rulelock = relation->rd_rules;
|
||||||
numlock = rulelock->numLocks;
|
numlock = rulelock->numLocks;
|
||||||
/* expand, for safety reasons */
|
/* expand, for safety reasons */
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
|
rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
|
||||||
sizeof(RewriteRule *) * (numlock + 1));
|
sizeof(RewriteRule *) * (numlock + 1));
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
@ -212,7 +212,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Assert(i < numlock);
|
Assert(i < numlock);
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
pfree(rulelock->rules[i]);
|
pfree(rulelock->rules[i]);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
if (numlock == 1)
|
if (numlock == 1)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.51 2000/05/30 00:49:52 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.52 2000/06/28 03:31:57 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -262,29 +262,23 @@ InitShmem(unsigned int key, unsigned int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ShmemAlloc -- allocate word-aligned byte string from
|
* ShmemAlloc -- allocate max-aligned byte string from shared memory
|
||||||
* shared memory
|
|
||||||
*
|
*
|
||||||
* Assumes ShmemLock and ShmemFreeStart are initialized.
|
* Assumes ShmemLock and ShmemFreeStart are initialized.
|
||||||
* Returns: real pointer to memory or NULL if we are out
|
* Returns: real pointer to memory or NULL if we are out
|
||||||
* of space. Has to return a real pointer in order
|
* of space. Has to return a real pointer in order
|
||||||
* to be compatable with malloc().
|
* to be compatible with malloc().
|
||||||
*/
|
*/
|
||||||
long *
|
void *
|
||||||
ShmemAlloc(unsigned long size)
|
ShmemAlloc(Size size)
|
||||||
{
|
{
|
||||||
unsigned long tmpFree;
|
unsigned long tmpFree;
|
||||||
long *newSpace;
|
void *newSpace;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ensure space is word aligned.
|
* ensure all space is adequately aligned.
|
||||||
*
|
|
||||||
* Word-alignment is not good enough. We have to be more conservative:
|
|
||||||
* doubles need 8-byte alignment. (We probably only need this on RISC
|
|
||||||
* platforms but this is not a big waste of space.) - ay 12/94
|
|
||||||
*/
|
*/
|
||||||
if (size % sizeof(double))
|
size = MAXALIGN(size);
|
||||||
size += sizeof(double) - (size % sizeof(double));
|
|
||||||
|
|
||||||
Assert(*ShmemFreeStart);
|
Assert(*ShmemFreeStart);
|
||||||
|
|
||||||
@ -293,7 +287,7 @@ ShmemAlloc(unsigned long size)
|
|||||||
tmpFree = *ShmemFreeStart + size;
|
tmpFree = *ShmemFreeStart + size;
|
||||||
if (tmpFree <= ShmemSize)
|
if (tmpFree <= ShmemSize)
|
||||||
{
|
{
|
||||||
newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
|
newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
|
||||||
*ShmemFreeStart += size;
|
*ShmemFreeStart += size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -302,7 +296,8 @@ ShmemAlloc(unsigned long size)
|
|||||||
SpinRelease(ShmemLock);
|
SpinRelease(ShmemLock);
|
||||||
|
|
||||||
if (!newSpace)
|
if (!newSpace)
|
||||||
elog(NOTICE, "ShmemAlloc: out of memory ");
|
elog(NOTICE, "ShmemAlloc: out of memory");
|
||||||
|
|
||||||
return newSpace;
|
return newSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +331,7 @@ ShmemInitHash(char *name, /* table string name for shmem index */
|
|||||||
int hash_flags) /* info about infoP */
|
int hash_flags) /* info about infoP */
|
||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
long *location;
|
void *location;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hash tables allocated in shared memory have a fixed directory; it
|
* Hash tables allocated in shared memory have a fixed directory; it
|
||||||
@ -478,12 +473,12 @@ ShmemPIDDestroy(int pid)
|
|||||||
* the object is already in the shmem index (hence, already
|
* the object is already in the shmem index (hence, already
|
||||||
* initialized).
|
* initialized).
|
||||||
*/
|
*/
|
||||||
long *
|
void *
|
||||||
ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
|
ShmemInitStruct(char *name, Size size, bool *foundPtr)
|
||||||
{
|
{
|
||||||
ShmemIndexEnt *result,
|
ShmemIndexEnt *result,
|
||||||
item;
|
item;
|
||||||
long *structPtr;
|
void *structPtr;
|
||||||
|
|
||||||
strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
|
strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
|
||||||
item.location = BAD_LOCATION;
|
item.location = BAD_LOCATION;
|
||||||
@ -498,27 +493,27 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the shmem index doesnt exist, we fake it.
|
* If the shmem index doesn't exist, we fake it.
|
||||||
*
|
*
|
||||||
* If we are creating the first shmem index, then let shmemalloc()
|
* If we are creating the first shmem index, then let shmemalloc()
|
||||||
* allocate the space for a new HTAB. Otherwise, find the old one
|
* allocate the space for a new HTAB. Otherwise, find the old one
|
||||||
* and return that. Notice that the ShmemIndexLock is held until
|
* and return that. Notice that the ShmemIndexLock is held until
|
||||||
* the shmem index has been completely initialized.
|
* the shmem index has been completely initialized.
|
||||||
*/
|
*/
|
||||||
Assert(!strcmp(name, strname));
|
Assert(strcmp(name, strname) == 0);
|
||||||
if (ShmemBootstrap)
|
if (ShmemBootstrap)
|
||||||
{
|
{
|
||||||
/* in POSTMASTER/Single process */
|
/* in POSTMASTER/Single process */
|
||||||
|
|
||||||
*foundPtr = FALSE;
|
*foundPtr = FALSE;
|
||||||
return (long *) ShmemAlloc(size);
|
return ShmemAlloc(size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Assert(ShmemIndexOffset);
|
Assert(ShmemIndexOffset);
|
||||||
|
|
||||||
*foundPtr = TRUE;
|
*foundPtr = TRUE;
|
||||||
return (long *) MAKE_PTR(*ShmemIndexOffset);
|
return (void *) MAKE_PTR(*ShmemIndexOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -554,12 +549,12 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
|
|||||||
/* let caller print its message too */
|
/* let caller print its message too */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
structPtr = (long *) MAKE_PTR(result->location);
|
structPtr = (void *) MAKE_PTR(result->location);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* It isn't in the table yet. allocate and initialize it */
|
/* It isn't in the table yet. allocate and initialize it */
|
||||||
structPtr = ShmemAlloc((long) size);
|
structPtr = ShmemAlloc(size);
|
||||||
if (!structPtr)
|
if (!structPtr)
|
||||||
{
|
{
|
||||||
/* out of memory */
|
/* out of memory */
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.71 2000/06/17 23:41:39 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.72 2000/06/28 03:32:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1090,7 +1090,7 @@ inv_newtuple(LargeObjectDesc *obj_desc,
|
|||||||
|
|
||||||
ntup->t_len = tupsize;
|
ntup->t_len = tupsize;
|
||||||
ItemPointerSet(&ntup->t_self, BufferGetBlockNumber(buffer), off);
|
ItemPointerSet(&ntup->t_self, BufferGetBlockNumber(buffer), off);
|
||||||
LastOidProcessed = ntup->t_data->t_oid = newoid();
|
ntup->t_data->t_oid = newoid();
|
||||||
TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_data->t_xmin));
|
TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_data->t_xmin));
|
||||||
ntup->t_data->t_cmin = GetCurrentCommandId();
|
ntup->t_data->t_cmin = GetCurrentCommandId();
|
||||||
StoreInvalidTransactionId(&(ntup->t_data->t_xmax));
|
StoreInvalidTransactionId(&(ntup->t_data->t_xmax));
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.69 2000/06/04 01:44:32 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.70 2000/06/28 03:32:07 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Outside modules can create a lock table and acquire/release
|
* Outside modules can create a lock table and acquire/release
|
||||||
@ -225,6 +225,11 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable,
|
|||||||
* has its name stored in the shmem index at its creation. It
|
* has its name stored in the shmem index at its creation. It
|
||||||
* is wasteful, in this case, but not much space is involved.
|
* is wasteful, in this case, but not much space is involved.
|
||||||
*
|
*
|
||||||
|
* NOTE: data structures allocated here are allocated permanently, using
|
||||||
|
* TopMemoryContext and shared memory. We don't ever release them anyway,
|
||||||
|
* and in normal multi-backend operation the lock table structures set up
|
||||||
|
* by the postmaster are inherited by each backend, so they must be in
|
||||||
|
* TopMemoryContext.
|
||||||
*/
|
*/
|
||||||
LOCKMETHOD
|
LOCKMETHOD
|
||||||
LockMethodTableInit(char *tabName,
|
LockMethodTableInit(char *tabName,
|
||||||
@ -246,22 +251,13 @@ LockMethodTableInit(char *tabName,
|
|||||||
return INVALID_LOCKMETHOD;
|
return INVALID_LOCKMETHOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate a string for the shmem index table lookup */
|
/* Allocate a string for the shmem index table lookups. */
|
||||||
shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32));
|
/* This is just temp space in this routine, so palloc is OK. */
|
||||||
if (!shmemName)
|
shmemName = (char *) palloc(strlen(tabName) + 32);
|
||||||
{
|
|
||||||
elog(NOTICE, "LockMethodTableInit: couldn't malloc string %s \n", tabName);
|
|
||||||
return INVALID_LOCKMETHOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* each lock table has a non-shared header */
|
/* each lock table has a non-shared, permanent header */
|
||||||
lockMethodTable = (LOCKMETHODTABLE *) palloc((unsigned) sizeof(LOCKMETHODTABLE));
|
lockMethodTable = (LOCKMETHODTABLE *)
|
||||||
if (!lockMethodTable)
|
MemoryContextAlloc(TopMemoryContext, sizeof(LOCKMETHODTABLE));
|
||||||
{
|
|
||||||
elog(NOTICE, "LockMethodTableInit: couldn't malloc lock table %s\n", tabName);
|
|
||||||
pfree(shmemName);
|
|
||||||
return INVALID_LOCKMETHOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------
|
/* ------------------------
|
||||||
* find/acquire the spinlock for the table
|
* find/acquire the spinlock for the table
|
||||||
@ -269,7 +265,6 @@ LockMethodTableInit(char *tabName,
|
|||||||
*/
|
*/
|
||||||
SpinAcquire(LockMgrLock);
|
SpinAcquire(LockMgrLock);
|
||||||
|
|
||||||
|
|
||||||
/* -----------------------
|
/* -----------------------
|
||||||
* allocate a control structure from shared memory or attach to it
|
* allocate a control structure from shared memory or attach to it
|
||||||
* if it already exists.
|
* if it already exists.
|
||||||
@ -277,7 +272,7 @@ LockMethodTableInit(char *tabName,
|
|||||||
*/
|
*/
|
||||||
sprintf(shmemName, "%s (ctl)", tabName);
|
sprintf(shmemName, "%s (ctl)", tabName);
|
||||||
lockMethodTable->ctl = (LOCKMETHODCTL *)
|
lockMethodTable->ctl = (LOCKMETHODCTL *)
|
||||||
ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found);
|
ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
|
||||||
|
|
||||||
if (!lockMethodTable->ctl)
|
if (!lockMethodTable->ctl)
|
||||||
{
|
{
|
||||||
@ -910,7 +905,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
|
|||||||
LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode);
|
LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode);
|
||||||
|
|
||||||
old_status = pstrdup(get_ps_display());
|
old_status = pstrdup(get_ps_display());
|
||||||
new_status = palloc(strlen(get_ps_display()) + 10);
|
new_status = (char *) palloc(strlen(get_ps_display()) + 10);
|
||||||
strcpy(new_status, get_ps_display());
|
strcpy(new_status, get_ps_display());
|
||||||
strcat(new_status, " waiting");
|
strcat(new_status, " waiting");
|
||||||
set_ps_display(new_status);
|
set_ps_display(new_status);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -47,7 +47,7 @@
|
|||||||
* This is so that we can support more backends. (system-wide semaphore
|
* This is so that we can support more backends. (system-wide semaphore
|
||||||
* sets run out pretty fast.) -ay 4/95
|
* sets run out pretty fast.) -ay 4/95
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -119,7 +119,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
|
|||||||
|
|
||||||
/* attach to the free list */
|
/* attach to the free list */
|
||||||
ProcGlobal = (PROC_HDR *)
|
ProcGlobal = (PROC_HDR *)
|
||||||
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
|
ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
|
||||||
|
|
||||||
/* --------------------
|
/* --------------------
|
||||||
* We're the first - initialize.
|
* We're the first - initialize.
|
||||||
@ -185,7 +185,7 @@ InitProcess(IPCKey key)
|
|||||||
|
|
||||||
/* attach to the free list */
|
/* attach to the free list */
|
||||||
ProcGlobal = (PROC_HDR *)
|
ProcGlobal = (PROC_HDR *)
|
||||||
ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
|
ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
/* this should not happen. InitProcGlobal() is called before this. */
|
/* this should not happen. InitProcGlobal() is called before this. */
|
||||||
@ -218,7 +218,7 @@ InitProcess(IPCKey key)
|
|||||||
* cleanup dead processes).
|
* cleanup dead processes).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
|
MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
|
||||||
if (!MyProc)
|
if (!MyProc)
|
||||||
{
|
{
|
||||||
SpinRelease(ProcStructLock);
|
SpinRelease(ProcStructLock);
|
||||||
@ -458,7 +458,7 @@ ProcQueueAlloc(char *name)
|
|||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
PROC_QUEUE *queue = (PROC_QUEUE *)
|
PROC_QUEUE *queue = (PROC_QUEUE *)
|
||||||
ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
|
ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
|
||||||
|
|
||||||
if (!queue)
|
if (!queue)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.71 2000/06/19 23:37:08 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.72 2000/06/28 03:32:14 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -94,19 +94,15 @@ static BlockNumber _mdnblocks(File file, Size blcksz);
|
|||||||
int
|
int
|
||||||
mdinit()
|
mdinit()
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
|
MdCxt = AllocSetContextCreate(TopMemoryContext,
|
||||||
if (MdCxt == (MemoryContext) NULL)
|
"MdSmgr",
|
||||||
return SM_FAIL;
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
Md_fdvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
|
||||||
Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
if (Md_fdvec == (MdfdVec *) NULL)
|
|
||||||
return SM_FAIL;
|
|
||||||
|
|
||||||
MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
|
MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
|
||||||
|
|
||||||
@ -208,7 +204,6 @@ mdunlink(Relation reln)
|
|||||||
int nblocks;
|
int nblocks;
|
||||||
int fd;
|
int fd;
|
||||||
MdfdVec *v;
|
MdfdVec *v;
|
||||||
MemoryContext oldcxt;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the relation is already unlinked,we have nothing to do any more.
|
* If the relation is already unlinked,we have nothing to do any more.
|
||||||
@ -238,7 +233,6 @@ mdunlink(Relation reln)
|
|||||||
|
|
||||||
Md_fdvec[fd].mdfd_flags = (uint16) 0;
|
Md_fdvec[fd].mdfd_flags = (uint16) 0;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
|
||||||
#ifndef LET_OS_MANAGE_FILESIZE
|
#ifndef LET_OS_MANAGE_FILESIZE
|
||||||
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
|
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
|
||||||
{
|
{
|
||||||
@ -256,7 +250,6 @@ mdunlink(Relation reln)
|
|||||||
FileTruncate(v->mdfd_vfd, 0);
|
FileTruncate(v->mdfd_vfd, 0);
|
||||||
FileUnlink(v->mdfd_vfd);
|
FileUnlink(v->mdfd_vfd);
|
||||||
#endif
|
#endif
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
_fdvec_free(fd);
|
_fdvec_free(fd);
|
||||||
|
|
||||||
@ -400,9 +393,7 @@ static void
|
|||||||
mdclose_fd(int fd)
|
mdclose_fd(int fd)
|
||||||
{
|
{
|
||||||
MdfdVec *v;
|
MdfdVec *v;
|
||||||
MemoryContext oldcxt;
|
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
|
||||||
#ifndef LET_OS_MANAGE_FILESIZE
|
#ifndef LET_OS_MANAGE_FILESIZE
|
||||||
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
|
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
|
||||||
{
|
{
|
||||||
@ -446,7 +437,6 @@ mdclose_fd(int fd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
_fdvec_free(fd);
|
_fdvec_free(fd);
|
||||||
}
|
}
|
||||||
@ -751,11 +741,8 @@ mdtruncate(Relation reln, int nblocks)
|
|||||||
int curnblk;
|
int curnblk;
|
||||||
int fd;
|
int fd;
|
||||||
MdfdVec *v;
|
MdfdVec *v;
|
||||||
|
|
||||||
#ifndef LET_OS_MANAGE_FILESIZE
|
#ifndef LET_OS_MANAGE_FILESIZE
|
||||||
MemoryContext oldcxt;
|
|
||||||
int priorblocks;
|
int priorblocks;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -772,7 +759,6 @@ mdtruncate(Relation reln, int nblocks)
|
|||||||
v = &Md_fdvec[fd];
|
v = &Md_fdvec[fd];
|
||||||
|
|
||||||
#ifndef LET_OS_MANAGE_FILESIZE
|
#ifndef LET_OS_MANAGE_FILESIZE
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
|
||||||
priorblocks = 0;
|
priorblocks = 0;
|
||||||
while (v != (MdfdVec *) NULL)
|
while (v != (MdfdVec *) NULL)
|
||||||
{
|
{
|
||||||
@ -825,7 +811,6 @@ mdtruncate(Relation reln, int nblocks)
|
|||||||
}
|
}
|
||||||
priorblocks += RELSEG_SIZE;
|
priorblocks += RELSEG_SIZE;
|
||||||
}
|
}
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
#else
|
#else
|
||||||
if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
|
if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -833,8 +818,7 @@ mdtruncate(Relation reln, int nblocks)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
return nblocks;
|
return nblocks;
|
||||||
|
}
|
||||||
} /* mdtruncate */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mdcommit() -- Commit a transaction.
|
* mdcommit() -- Commit a transaction.
|
||||||
@ -907,7 +891,6 @@ _fdvec_alloc()
|
|||||||
MdfdVec *nvec;
|
MdfdVec *nvec;
|
||||||
int fdvec,
|
int fdvec,
|
||||||
i;
|
i;
|
||||||
MemoryContext oldcxt;
|
|
||||||
|
|
||||||
if (Md_Free >= 0) /* get from free list */
|
if (Md_Free >= 0) /* get from free list */
|
||||||
{
|
{
|
||||||
@ -930,15 +913,11 @@ _fdvec_alloc()
|
|||||||
|
|
||||||
Nfds *= 2;
|
Nfds *= 2;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
nvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
|
||||||
|
|
||||||
nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
|
|
||||||
MemSet(nvec, 0, Nfds * sizeof(MdfdVec));
|
MemSet(nvec, 0, Nfds * sizeof(MdfdVec));
|
||||||
memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
|
memcpy(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
|
||||||
pfree(Md_fdvec);
|
pfree(Md_fdvec);
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
Md_fdvec = nvec;
|
Md_fdvec = nvec;
|
||||||
|
|
||||||
/* Set new free list */
|
/* Set new free list */
|
||||||
@ -976,7 +955,6 @@ _fdvec_free(int fdvec)
|
|||||||
static MdfdVec *
|
static MdfdVec *
|
||||||
_mdfd_openseg(Relation reln, int segno, int oflags)
|
_mdfd_openseg(Relation reln, int segno, int oflags)
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
|
||||||
MdfdVec *v;
|
MdfdVec *v;
|
||||||
int fd;
|
int fd;
|
||||||
char *path,
|
char *path,
|
||||||
@ -1003,9 +981,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags)
|
|||||||
return (MdfdVec *) NULL;
|
return (MdfdVec *) NULL;
|
||||||
|
|
||||||
/* allocate an mdfdvec entry for it */
|
/* allocate an mdfdvec entry for it */
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
v = (MdfdVec *) MemoryContextAlloc(MdCxt, sizeof(MdfdVec));
|
||||||
v = (MdfdVec *) palloc(sizeof(MdfdVec));
|
|
||||||
MemoryContextSwitchTo(oldcxt);
|
|
||||||
|
|
||||||
/* fill the entry */
|
/* fill the entry */
|
||||||
v->mdfd_vfd = fd;
|
v->mdfd_vfd = fd;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.161 2000/06/22 22:31:20 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.162 2000/06/28 03:32:18 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
@ -79,7 +79,6 @@ bool Log_connections = false;
|
|||||||
CommandDest whereToSendOutput = Debug;
|
CommandDest whereToSendOutput = Debug;
|
||||||
|
|
||||||
|
|
||||||
extern void BaseInit(void);
|
|
||||||
extern void StartupXLOG(void);
|
extern void StartupXLOG(void);
|
||||||
extern void ShutdownXLOG(void);
|
extern void ShutdownXLOG(void);
|
||||||
|
|
||||||
@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS);
|
|||||||
extern char XLogDir[];
|
extern char XLogDir[];
|
||||||
extern char ControlFilePath[];
|
extern char ControlFilePath[];
|
||||||
|
|
||||||
extern int lockingOff;
|
static bool dontExecute = false;
|
||||||
extern int NBuffers;
|
|
||||||
|
|
||||||
int dontExecute = 0;
|
|
||||||
static bool IsEmptyQuery = false;
|
static bool IsEmptyQuery = false;
|
||||||
|
|
||||||
/* note: these declarations had better match tcopprot.h */
|
/* note: these declarations had better match tcopprot.h */
|
||||||
@ -101,8 +98,6 @@ bool Warn_restart_ready = false;
|
|||||||
bool InError = false;
|
bool InError = false;
|
||||||
bool ExitAfterAbort = false;
|
bool ExitAfterAbort = false;
|
||||||
|
|
||||||
extern int NBuffers;
|
|
||||||
|
|
||||||
static bool EchoQuery = false; /* default don't echo */
|
static bool EchoQuery = false; /* default don't echo */
|
||||||
char pg_pathname[MAXPGPATH];
|
char pg_pathname[MAXPGPATH];
|
||||||
FILE *StatFp = NULL;
|
FILE *StatFp = NULL;
|
||||||
@ -133,7 +128,6 @@ int XfuncMode = 0;
|
|||||||
static int InteractiveBackend(StringInfo inBuf);
|
static int InteractiveBackend(StringInfo inBuf);
|
||||||
static int SocketBackend(StringInfo inBuf);
|
static int SocketBackend(StringInfo inBuf);
|
||||||
static int ReadCommand(StringInfo inBuf);
|
static int ReadCommand(StringInfo inBuf);
|
||||||
static void pg_exec_query(char *query_string);
|
|
||||||
static void SigHupHandler(SIGNAL_ARGS);
|
static void SigHupHandler(SIGNAL_ARGS);
|
||||||
static void FloatExceptionHandler(SIGNAL_ARGS);
|
static void FloatExceptionHandler(SIGNAL_ARGS);
|
||||||
static void quickdie(SIGNAL_ARGS);
|
static void quickdie(SIGNAL_ARGS);
|
||||||
@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf)
|
|||||||
static int
|
static int
|
||||||
ReadCommand(StringInfo inBuf)
|
ReadCommand(StringInfo inBuf)
|
||||||
{
|
{
|
||||||
MemoryContext oldcontext;
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure any expansion of inBuf happens in permanent memory
|
|
||||||
* context, so that we can keep using it for future command cycles.
|
|
||||||
*/
|
|
||||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
|
||||||
if (IsUnderPostmaster)
|
if (IsUnderPostmaster)
|
||||||
result = SocketBackend(inBuf);
|
result = SocketBackend(inBuf);
|
||||||
else
|
else
|
||||||
result = InteractiveBackend(inBuf);
|
result = InteractiveBackend(inBuf);
|
||||||
MemoryContextSwitchTo(oldcontext);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf)
|
|||||||
* multiple queries and/or the rewriter might expand one query to several.
|
* multiple queries and/or the rewriter might expand one query to several.
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
pg_parse_and_rewrite(char *query_string, /* string to execute */
|
pg_parse_and_rewrite(char *query_string, /* string to execute */
|
||||||
Oid *typev,/* argument types */
|
Oid *typev, /* parameter types */
|
||||||
int nargs, /* number of arguments */
|
int nargs) /* number of parameters */
|
||||||
bool aclOverride)
|
|
||||||
{
|
{
|
||||||
List *querytree_list;
|
List *querytree_list;
|
||||||
List *querytree_list_item;
|
List *querytree_list_item;
|
||||||
@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
|
|||||||
|
|
||||||
querytree_list = new_list;
|
querytree_list = new_list;
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* (3) If ACL override is requested, mark queries for no ACL check.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
if (aclOverride)
|
|
||||||
{
|
|
||||||
foreach(querytree_list_item, querytree_list)
|
|
||||||
{
|
|
||||||
List *l;
|
|
||||||
|
|
||||||
querytree = (Query *) lfirst(querytree_list_item);
|
|
||||||
|
|
||||||
if (querytree->commandType == CMD_UTILITY)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach(l, querytree->rtable)
|
|
||||||
{
|
|
||||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
|
||||||
|
|
||||||
rte->skipAcl = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Debug_print_rewritten)
|
if (Debug_print_rewritten)
|
||||||
{
|
{
|
||||||
if (Debug_pretty_print)
|
if (Debug_pretty_print)
|
||||||
@ -516,63 +478,66 @@ pg_plan_query(Query *querytree)
|
|||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* pg_exec_query()
|
* pg_exec_query_dest()
|
||||||
*
|
*
|
||||||
* Takes a querystring, runs the parser/utilities or
|
* Takes a querystring, runs the parser/utilities or
|
||||||
* parser/planner/executor over it as necessary
|
* parser/planner/executor over it as necessary.
|
||||||
* Begin Transaction Should have been called before this
|
|
||||||
* and CommitTransaction After this is called
|
|
||||||
* This is strictly because we do not allow for nested xactions.
|
|
||||||
*
|
*
|
||||||
* NON-OBVIOUS-RESTRICTIONS
|
* Assumptions:
|
||||||
* this function _MUST_ allocate a new "parsetree" each time,
|
*
|
||||||
* since it may be stored in a named portal and should not
|
* Caller is responsible for calling StartTransactionCommand() beforehand
|
||||||
* change its value.
|
* 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
|
void
|
||||||
pg_exec_query_dest(char *query_string, /* string to execute */
|
pg_exec_query_dest(char *query_string, /* string to execute */
|
||||||
CommandDest dest, /* where results should go */
|
CommandDest dest, /* where results should go */
|
||||||
bool aclOverride) /* to give utility commands power
|
MemoryContext parse_context) /* context for parsetrees */
|
||||||
* of superusers */
|
|
||||||
{
|
{
|
||||||
List *querytree_list;
|
MemoryContext oldcontext;
|
||||||
|
List *querytree_list,
|
||||||
/* parse and rewrite the queries */
|
*querytree_item;
|
||||||
querytree_list = pg_parse_and_rewrite(query_string, NULL, 0,
|
|
||||||
aclOverride);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: we do not use "foreach" here because we want to be sure the
|
* Switch to appropriate context for constructing parsetrees.
|
||||||
* list pointer has been advanced before the query is executed. We
|
|
||||||
* need to do that because VACUUM has a nasty little habit of doing
|
|
||||||
* CommitTransactionCommand at startup, and that will release the
|
|
||||||
* memory holding our parse list :-(. This needs a better solution
|
|
||||||
* --- currently, the code will crash if someone submits "vacuum;
|
|
||||||
* something-else" in a single query string. But memory allocation
|
|
||||||
* needs redesigned anyway, so this will have to do for now.
|
|
||||||
*/
|
*/
|
||||||
while (querytree_list)
|
oldcontext = MemoryContextSwitchTo(parse_context);
|
||||||
{
|
|
||||||
Query *querytree = (Query *) lfirst(querytree_list);
|
|
||||||
|
|
||||||
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 we got a cancel signal in parsing or prior command, quit */
|
||||||
if (QueryCancel)
|
if (QueryCancel)
|
||||||
@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string, /* string to execute */
|
|||||||
if (Show_executor_stats)
|
if (Show_executor_stats)
|
||||||
ResetUsage();
|
ResetUsage();
|
||||||
|
|
||||||
if (DebugLvl > 1)
|
if (dontExecute)
|
||||||
elog(DEBUG, "ProcessQuery");
|
{
|
||||||
ProcessQuery(querytree, plan, dest);
|
/* don't execute it, just show the query plan */
|
||||||
|
print_plan(plan, querytree);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (DebugLvl > 1)
|
||||||
|
elog(DEBUG, "ProcessQuery");
|
||||||
|
ProcessQuery(querytree, plan, dest);
|
||||||
|
}
|
||||||
|
|
||||||
if (Show_executor_stats)
|
if (Show_executor_stats)
|
||||||
{
|
{
|
||||||
@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string, /* string to execute */
|
|||||||
* between queries so that the effects of early queries are
|
* between queries so that the effects of early queries are
|
||||||
* visible to subsequent ones.
|
* visible to subsequent ones.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CommandCounterIncrement();
|
CommandCounterIncrement();
|
||||||
|
/*
|
||||||
|
* Also, clear the execution context to recover temporary
|
||||||
|
* memory used by the query. NOTE: if query string contains
|
||||||
|
* BEGIN/COMMIT transaction commands, execution context may
|
||||||
|
* now be different from what we were originally passed;
|
||||||
|
* so be careful to clear current context not "oldcontext".
|
||||||
|
*/
|
||||||
|
MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,6 +801,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int DebugLvl;
|
extern int DebugLvl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fire up essential subsystems: error and memory management
|
||||||
|
*
|
||||||
|
* If we are running under the postmaster, this is done already.
|
||||||
|
*/
|
||||||
|
if (!IsUnderPostmaster)
|
||||||
|
{
|
||||||
|
EnableExceptionHandling(true);
|
||||||
|
MemoryContextInit();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set default values for command-line options.
|
* Set default values for command-line options.
|
||||||
*/
|
*/
|
||||||
@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
dontExecute = 1;
|
dontExecute = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
@ -1182,11 +1173,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
*
|
*
|
||||||
* Note that postmaster already blocked ALL signals to make us happy.
|
* Note that postmaster already blocked ALL signals to make us happy.
|
||||||
*/
|
*/
|
||||||
if (!IsUnderPostmaster)
|
pqinitmask();
|
||||||
{
|
|
||||||
PG_INITMASK();
|
|
||||||
PG_SETMASK(&BlockSig);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_SIGPROCMASK
|
#ifdef HAVE_SIGPROCMASK
|
||||||
sigdelset(&BlockSig, SIGUSR1);
|
sigdelset(&BlockSig, SIGUSR1);
|
||||||
@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
BlockSig &= ~(sigmask(SIGUSR1));
|
BlockSig &= ~(sigmask(SIGUSR1));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
|
||||||
|
|
||||||
pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
|
pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
|
||||||
pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
|
pqsignal(SIGINT, QueryCancelHandler); /* cancel current query */
|
||||||
pqsignal(SIGQUIT, handle_warn); /* handle error */
|
pqsignal(SIGQUIT, handle_warn); /* handle error */
|
||||||
@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
pqsignal(SIGTTOU, SIG_DFL);
|
pqsignal(SIGTTOU, SIG_DFL);
|
||||||
pqsignal(SIGCONT, SIG_DFL);
|
pqsignal(SIGCONT, SIG_DFL);
|
||||||
|
|
||||||
PG_SETMASK(&BlockSig); /* block everything except SIGUSR1 */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get user name (needed now in case it is the default database name)
|
* Get user name (needed now in case it is the default database name)
|
||||||
* and check command line validity
|
* and check command line validity
|
||||||
@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
|
|
||||||
on_shmem_exit(remove_all_temp_relations, NULL);
|
on_shmem_exit(remove_all_temp_relations, NULL);
|
||||||
|
|
||||||
{
|
|
||||||
MemoryContext oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
|
||||||
|
|
||||||
parser_input = makeStringInfo(); /* initialize input buffer */
|
|
||||||
MemoryContextSwitchTo(oldcontext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send this backend's cancellation info to the frontend.
|
* Send this backend's cancellation info to the frontend.
|
||||||
*/
|
*/
|
||||||
@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface ");
|
puts("\nPOSTGRES backend interactive interface ");
|
||||||
puts("$Revision: 1.161 $ $Date: 2000/06/22 22:31:20 $\n");
|
puts("$Revision: 1.162 $ $Date: 2000/06/28 03:32:18 $\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1397,6 +1377,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
|
|
||||||
SetProcessingMode(NormalProcessing);
|
SetProcessingMode(NormalProcessing);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the memory context we will use in the main loop.
|
||||||
|
*
|
||||||
|
* QueryContext is reset once per iteration of the main loop,
|
||||||
|
* ie, upon completion of processing of each supplied query string.
|
||||||
|
* It can therefore be used for any data that should live just as
|
||||||
|
* long as the query string --- parse trees, for example.
|
||||||
|
*/
|
||||||
|
QueryContext = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"QueryContext",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* POSTGRES main processing loop begins here
|
* POSTGRES main processing loop begins here
|
||||||
*
|
*
|
||||||
@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
|
|
||||||
if (sigsetjmp(Warn_restart, 1) != 0)
|
if (sigsetjmp(Warn_restart, 1) != 0)
|
||||||
{
|
{
|
||||||
/* Make sure we are in a valid memory context */
|
/*
|
||||||
MemoryContextSwitchTo(TopMemoryContext);
|
* Make sure we are in a valid memory context during recovery.
|
||||||
|
*
|
||||||
|
* We use ErrorContext in hopes that it will have some free space
|
||||||
|
* even if we're otherwise up against it...
|
||||||
|
*/
|
||||||
|
MemoryContextSwitchTo(ErrorContext);
|
||||||
|
|
||||||
if (DebugLvl >= 1)
|
if (DebugLvl >= 1)
|
||||||
elog(DEBUG, "AbortCurrentTransaction");
|
elog(DEBUG, "AbortCurrentTransaction");
|
||||||
AbortCurrentTransaction();
|
AbortCurrentTransaction();
|
||||||
InError = false;
|
|
||||||
if (ExitAfterAbort)
|
if (ExitAfterAbort)
|
||||||
{
|
{
|
||||||
ProcReleaseLocks(); /* Just to be sure... */
|
ProcReleaseLocks(); /* Just to be sure... */
|
||||||
proc_exit(0);
|
proc_exit(0);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* If we recovered successfully, return to normal top-level context
|
||||||
|
* and clear ErrorContext for next time.
|
||||||
|
*/
|
||||||
|
MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
MemoryContextResetAndDeleteChildren(ErrorContext);
|
||||||
|
InError = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Warn_restart_ready = true; /* we can now handle elog(ERROR) */
|
Warn_restart_ready = true; /* we can now handle elog(ERROR) */
|
||||||
@ -1430,7 +1436,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
set_ps_display("idle");
|
/*
|
||||||
|
* Release storage left over from prior query cycle, and
|
||||||
|
* create a new query input buffer in the cleared QueryContext.
|
||||||
|
*/
|
||||||
|
MemoryContextSwitchTo(QueryContext);
|
||||||
|
MemoryContextResetAndDeleteChildren(QueryContext);
|
||||||
|
|
||||||
|
parser_input = makeStringInfo();
|
||||||
|
|
||||||
/* XXX this could be moved after ReadCommand below to get more
|
/* XXX this could be moved after ReadCommand below to get more
|
||||||
* sensical behaviour */
|
* sensical behaviour */
|
||||||
@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
* (3) read a command (loop blocks here)
|
* (3) read a command (loop blocks here)
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
set_ps_display("idle");
|
||||||
|
|
||||||
firstchar = ReadCommand(parser_input);
|
firstchar = ReadCommand(parser_input);
|
||||||
|
|
||||||
QueryCancel = false; /* forget any earlier CANCEL signal */
|
QueryCancel = false; /* forget any earlier CANCEL signal */
|
||||||
@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
elog(DEBUG, "StartTransactionCommand");
|
elog(DEBUG, "StartTransactionCommand");
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
|
|
||||||
pg_exec_query(parser_input->data);
|
pg_exec_query_dest(parser_input->data,
|
||||||
|
whereToSendOutput,
|
||||||
|
QueryContext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invoke IMMEDIATE constraint triggers
|
* Invoke IMMEDIATE constraint triggers
|
||||||
@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
* (6) commit the current transaction
|
* (6) commit the current transaction
|
||||||
*
|
*
|
||||||
* Note: if we had an empty input buffer, then we didn't
|
* Note: if we had an empty input buffer, then we didn't
|
||||||
* call pg_exec_query, so we don't bother to commit this transaction.
|
* call pg_exec_query_dest, so we don't bother to commit
|
||||||
|
* this transaction.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!IsEmptyQuery)
|
if (!IsEmptyQuery)
|
||||||
@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
|||||||
#ifdef SHOW_MEMORY_STATS
|
#ifdef SHOW_MEMORY_STATS
|
||||||
/* print global-context stats at each commit for leak tracking */
|
/* print global-context stats at each commit for leak tracking */
|
||||||
if (ShowStats)
|
if (ShowStats)
|
||||||
GlobalMemoryStats();
|
MemoryContextStats(TopMemoryContext);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.34 2000/06/12 03:40:40 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.35 2000/06/28 03:32:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -22,8 +22,6 @@
|
|||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
|
|
||||||
static char *CreateOperationTag(int operationType);
|
static char *CreateOperationTag(int operationType);
|
||||||
static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
|
|
||||||
Node *limcount);
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@ -115,7 +113,7 @@ CreateOperationTag(int operationType)
|
|||||||
default:
|
default:
|
||||||
elog(DEBUG, "CreateOperationTag: unknown operation type %d",
|
elog(DEBUG, "CreateOperationTag: unknown operation type %d",
|
||||||
operationType);
|
operationType);
|
||||||
tag = NULL;
|
tag = "???";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,31 +121,18 @@ CreateOperationTag(int operationType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* ProcessPortal
|
* PreparePortal
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
Portal
|
||||||
void
|
PreparePortal(char *portalName)
|
||||||
ProcessPortal(char *portalName,
|
|
||||||
Query *parseTree,
|
|
||||||
Plan *plan,
|
|
||||||
EState *state,
|
|
||||||
TupleDesc attinfo,
|
|
||||||
CommandDest dest)
|
|
||||||
{
|
{
|
||||||
Portal portal;
|
Portal portal;
|
||||||
MemoryContext portalContext;
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Check for reserved or already-in-use portal name.
|
* Check for already-in-use portal name.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (PortalNameIsSpecial(portalName))
|
|
||||||
elog(ERROR,
|
|
||||||
"The portal name \"%s\" is reserved for internal use",
|
|
||||||
portalName);
|
|
||||||
|
|
||||||
portal = GetPortalByName(portalName);
|
portal = GetPortalByName(portalName);
|
||||||
if (PortalIsValid(portal))
|
if (PortalIsValid(portal))
|
||||||
{
|
{
|
||||||
@ -158,70 +143,39 @@ ProcessPortal(char *portalName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Convert the current blank portal into the user-specified
|
* Create the new portal and make its memory context active.
|
||||||
* portal and initialize the state and query descriptor.
|
|
||||||
*
|
|
||||||
* Since the parsetree has been created in the current blank portal,
|
|
||||||
* we don't have to do any work to copy it into the user-named portal.
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
portal = CreatePortal(portalName);
|
||||||
|
|
||||||
portal = BlankPortalAssignName(portalName);
|
MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
PortalSetQuery(portal,
|
return 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ProcessQueryDesc
|
* ProcessQuery
|
||||||
*
|
*
|
||||||
* Read the comments for ProcessQuery() below...
|
* Execute a plan, the non-parallel version
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
ProcessQuery(Query *parsetree,
|
||||||
|
Plan *plan,
|
||||||
|
CommandDest dest)
|
||||||
{
|
{
|
||||||
Query *parseTree;
|
int operation = parsetree->commandType;
|
||||||
Plan *plan;
|
char *tag;
|
||||||
int operation;
|
bool isRetrieveIntoPortal;
|
||||||
char *tag = NULL;
|
bool isRetrieveIntoRelation;
|
||||||
|
Portal portal = NULL;
|
||||||
|
char *intoName = NULL;
|
||||||
|
QueryDesc *queryDesc;
|
||||||
EState *state;
|
EState *state;
|
||||||
TupleDesc attinfo;
|
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));
|
set_ps_display(tag = CreateOperationTag(operation));
|
||||||
dest = queryDesc->dest;
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* initialize portal/into relation status
|
* initialize portal/into relation status
|
||||||
@ -232,11 +186,11 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||||||
|
|
||||||
if (operation == CMD_SELECT)
|
if (operation == CMD_SELECT)
|
||||||
{
|
{
|
||||||
if (parseTree->isPortal)
|
if (parsetree->isPortal)
|
||||||
{
|
{
|
||||||
isRetrieveIntoPortal = true;
|
isRetrieveIntoPortal = true;
|
||||||
intoName = parseTree->into;
|
intoName = parsetree->into;
|
||||||
if (parseTree->isBinary)
|
if (parsetree->isBinary)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -244,19 +198,38 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||||||
* (externalized form) to RemoteInternal (internalized
|
* (externalized form) to RemoteInternal (internalized
|
||||||
* form)
|
* form)
|
||||||
*/
|
*/
|
||||||
dest = queryDesc->dest = RemoteInternal;
|
dest = RemoteInternal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parseTree->into != NULL)
|
else if (parsetree->into != NULL)
|
||||||
{
|
{
|
||||||
/* select into table */
|
/* select into table */
|
||||||
isRetrieveIntoRelation = true;
|
isRetrieveIntoRelation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* 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
|
* communication destination during the processing of the
|
||||||
* the query. This only affects the tuple-output function
|
* the query. This only affects the tuple-output function
|
||||||
* - the correct destination will still see BeginCommand()
|
* - the correct destination will still see BeginCommand()
|
||||||
@ -293,26 +266,19 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||||||
dest);
|
dest);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Named portals do not do a "fetch all" initially, so now
|
* If retrieve into portal, stop now; we do not run the plan
|
||||||
* we return since ExecMain has been called with EXEC_START
|
* until a FETCH command is received.
|
||||||
* to initialize the query plan.
|
|
||||||
*
|
|
||||||
* Note: ProcessPortal transforms the current "blank" portal
|
|
||||||
* into a named portal and creates a new blank portal so
|
|
||||||
* everything we allocated in the current "blank" memory
|
|
||||||
* context will be preserved across queries. -cim 2/22/91
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (isRetrieveIntoPortal)
|
if (isRetrieveIntoPortal)
|
||||||
{
|
{
|
||||||
PortalExecutorHeapMemory = NULL;
|
PortalSetQuery(portal,
|
||||||
|
queryDesc,
|
||||||
|
attinfo,
|
||||||
|
state,
|
||||||
|
PortalCleanup);
|
||||||
|
|
||||||
ProcessPortal(intoName,
|
MemoryContextSwitchTo(TransactionCommandContext);
|
||||||
parseTree,
|
|
||||||
plan,
|
|
||||||
state,
|
|
||||||
attinfo,
|
|
||||||
dest);
|
|
||||||
|
|
||||||
EndCommand(tag, dest);
|
EndCommand(tag, dest);
|
||||||
return;
|
return;
|
||||||
@ -323,14 +289,14 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||||||
* actually run the plan..
|
* actually run the plan..
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
|
ExecutorRun(queryDesc, state, EXEC_RUN,
|
||||||
|
parsetree->limitOffset, parsetree->limitCount);
|
||||||
|
|
||||||
/* save infos for EndCommand */
|
/* save infos for EndCommand */
|
||||||
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* now, we close down all the scans and free allocated resources...
|
* Now, we close down all the scans and free allocated resources.
|
||||||
* with ExecutorEnd()
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
ExecutorEnd(queryDesc, state);
|
ExecutorEnd(queryDesc, state);
|
||||||
@ -341,31 +307,3 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
|
|||||||
*/
|
*/
|
||||||
EndCommand(tag, dest);
|
EndCommand(tag, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
|
||||||
* ProcessQuery
|
|
||||||
*
|
|
||||||
* Execute a plan, the non-parallel version
|
|
||||||
* ----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
ProcessQuery(Query *parsetree,
|
|
||||||
Plan *plan,
|
|
||||||
CommandDest dest)
|
|
||||||
{
|
|
||||||
QueryDesc *queryDesc;
|
|
||||||
extern int dontExecute; /* from postgres.c */
|
|
||||||
extern void print_plan(Plan *p, Query *parsetree); /* from print.c */
|
|
||||||
|
|
||||||
queryDesc = CreateQueryDesc(parsetree, plan, dest);
|
|
||||||
|
|
||||||
if (dontExecute)
|
|
||||||
{
|
|
||||||
/* don't execute it, just show the query plan */
|
|
||||||
print_plan(plan, parsetree);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ProcessQueryDesc(queryDesc, parsetree->limitOffset,
|
|
||||||
parsetree->limitCount);
|
|
||||||
}
|
|
||||||
|
91
src/backend/utils/cache/catcache.c
vendored
91
src/backend/utils/cache/catcache.c
vendored
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.67 2000/06/19 03:54:31 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.68 2000/06/28 03:32:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -60,10 +60,6 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
|
|||||||
|
|
||||||
static CatCache *Caches = NULL; /* head of list of caches */
|
static CatCache *Caches = NULL; /* head of list of caches */
|
||||||
|
|
||||||
GlobalMemory CacheCxt; /* context in which caches are allocated */
|
|
||||||
|
|
||||||
/* CacheCxt is global because relcache uses it too. */
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* EQPROC is used in CatalogCacheInitializeCache to find the equality
|
* EQPROC is used in CatalogCacheInitializeCache to find the equality
|
||||||
@ -135,6 +131,28 @@ cc_hashname(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standard routine for creating cache context if it doesn't exist yet
|
||||||
|
*
|
||||||
|
* There are a lot of places (probably far more than necessary) that check
|
||||||
|
* whether CacheMemoryContext exists yet and want to create it if not.
|
||||||
|
* We centralize knowledge of exactly how to create it here.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
CreateCacheMemoryContext(void)
|
||||||
|
{
|
||||||
|
/* Purely for paranoia, check that context doesn't exist;
|
||||||
|
* caller probably did so already.
|
||||||
|
*/
|
||||||
|
if (!CacheMemoryContext)
|
||||||
|
CacheMemoryContext = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"CacheMemoryContext",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* CatalogCacheInitializeCache
|
* CatalogCacheInitializeCache
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
@ -183,9 +201,10 @@ CatalogCacheInitializeCache(CatCache * cache,
|
|||||||
* do not vanish at the end of a transaction
|
* do not vanish at the end of a transaction
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* If no relation was passed we must open it to get access to
|
* If no relation was passed we must open it to get access to
|
||||||
@ -415,7 +434,7 @@ CatalogCacheComputeTupleHashIndex(CatCache * cacheInOutP,
|
|||||||
/* --------------------------------
|
/* --------------------------------
|
||||||
* CatCacheRemoveCTup
|
* CatCacheRemoveCTup
|
||||||
*
|
*
|
||||||
* NB: assumes caller has switched to CacheCxt
|
* NB: assumes caller has switched to CacheMemoryContext
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
@ -477,9 +496,10 @@ CatalogCacheIdInvalidate(int cacheId, /* XXX */
|
|||||||
* switch to the cache context for our memory allocations
|
* switch to the cache context for our memory allocations
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* inspect every cache that could contain the tuple
|
* inspect every cache that could contain the tuple
|
||||||
@ -552,10 +572,10 @@ ResetSystemCache()
|
|||||||
* do not vanish at the end of a transaction
|
* do not vanish at the end of a transaction
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* here we purge the contents of all the caches
|
* here we purge the contents of all the caches
|
||||||
@ -681,10 +701,10 @@ InitSysCache(char *relname,
|
|||||||
* do not vanish at the end of a transaction
|
* do not vanish at the end of a transaction
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* allocate a new cache structure
|
* allocate a new cache structure
|
||||||
@ -839,14 +859,14 @@ SearchSelfReferences(CatCache * cache)
|
|||||||
HeapScanDesc sd;
|
HeapScanDesc sd;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
if (!CacheCxt)
|
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
|
||||||
rel = heap_open(cache->relationId, AccessShareLock);
|
rel = heap_open(cache->relationId, AccessShareLock);
|
||||||
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
|
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
|
||||||
ntp = heap_getnext(sd, 0);
|
ntp = heap_getnext(sd, 0);
|
||||||
if (!HeapTupleIsValid(ntp))
|
if (!HeapTupleIsValid(ntp))
|
||||||
elog(ERROR, "SearchSelfReferences: tuple not found");
|
elog(ERROR, "SearchSelfReferences: tuple not found");
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
if (!CacheMemoryContext)
|
||||||
|
CreateCacheMemoryContext();
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
indexSelfTuple = heap_copytuple(ntp);
|
indexSelfTuple = heap_copytuple(ntp);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
heap_endscan(sd);
|
heap_endscan(sd);
|
||||||
@ -868,14 +888,14 @@ SearchSelfReferences(CatCache * cache)
|
|||||||
HeapScanDesc sd;
|
HeapScanDesc sd;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
if (!CacheCxt)
|
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
|
||||||
rel = heap_open(cache->relationId, AccessShareLock);
|
rel = heap_open(cache->relationId, AccessShareLock);
|
||||||
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
|
sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
|
||||||
ntp = heap_getnext(sd, 0);
|
ntp = heap_getnext(sd, 0);
|
||||||
if (!HeapTupleIsValid(ntp))
|
if (!HeapTupleIsValid(ntp))
|
||||||
elog(ERROR, "SearchSelfReferences: tuple not found");
|
elog(ERROR, "SearchSelfReferences: tuple not found");
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
if (!CacheMemoryContext)
|
||||||
|
CreateCacheMemoryContext();
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
|
operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
heap_endscan(sd);
|
heap_endscan(sd);
|
||||||
@ -908,7 +928,6 @@ SearchSysCache(CatCache * cache,
|
|||||||
CatCTup *nct2;
|
CatCTup *nct2;
|
||||||
Dlelem *elt;
|
Dlelem *elt;
|
||||||
HeapTuple ntp = NULL;
|
HeapTuple ntp = NULL;
|
||||||
|
|
||||||
Relation relation;
|
Relation relation;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
@ -1020,10 +1039,10 @@ SearchSysCache(CatCache * cache,
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Scan the relation to find the tuple. If there's an index, and
|
* Scan the relation to find the tuple. If there's an index, and
|
||||||
@ -1060,12 +1079,13 @@ SearchSysCache(CatCache * cache,
|
|||||||
*/
|
*/
|
||||||
if (HeapTupleIsValid(indextp))
|
if (HeapTupleIsValid(indextp))
|
||||||
{
|
{
|
||||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
ntp = heap_copytuple(indextp);
|
ntp = heap_copytuple(indextp);
|
||||||
|
/* this switch is probably not needed anymore: */
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
heap_freetuple(indextp);
|
heap_freetuple(indextp);
|
||||||
}
|
}
|
||||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1084,7 +1104,7 @@ SearchSysCache(CatCache * cache,
|
|||||||
|
|
||||||
ntp = heap_getnext(sd, 0);
|
ntp = heap_getnext(sd, 0);
|
||||||
|
|
||||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
if (HeapTupleIsValid(ntp))
|
if (HeapTupleIsValid(ntp))
|
||||||
{
|
{
|
||||||
@ -1097,7 +1117,7 @@ SearchSysCache(CatCache * cache,
|
|||||||
|
|
||||||
heap_endscan(sd);
|
heap_endscan(sd);
|
||||||
|
|
||||||
MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->busy = false;
|
cache->busy = false;
|
||||||
@ -1205,9 +1225,10 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
|
|||||||
* switch to the cache memory context
|
* switch to the cache memory context
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* for each cache
|
* for each cache
|
||||||
|
25
src/backend/utils/cache/relcache.c
vendored
25
src/backend/utils/cache/relcache.c
vendored
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.103 2000/06/19 23:40:48 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.104 2000/06/28 03:32:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -917,10 +917,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* allocate storage for the relation descriptor,
|
* allocate storage for the relation descriptor,
|
||||||
* initialize relation->rd_rel and get the access method id.
|
* initialize relation->rd_rel and get the access method id.
|
||||||
* The storage is allocated in memory context CacheCxt.
|
* The storage is allocated in memory context CacheMemoryContext.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
relation = AllocateRelationDesc(oldrelation, natts, relp);
|
relation = AllocateRelationDesc(oldrelation, natts, relp);
|
||||||
relam = relation->rd_rel->relam;
|
relam = relation->rd_rel->relam;
|
||||||
|
|
||||||
@ -1383,7 +1383,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
|
|||||||
if (relation->rd_isnailed)
|
if (relation->rd_isnailed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove relation from hash tables
|
* Remove relation from hash tables
|
||||||
@ -1574,7 +1574,7 @@ RelationForgetRelation(Oid rid)
|
|||||||
List *curr;
|
List *curr;
|
||||||
List *prev = NIL;
|
List *prev = NIL;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
foreach(curr, newlyCreatedRelns)
|
foreach(curr, newlyCreatedRelns)
|
||||||
{
|
{
|
||||||
@ -1731,10 +1731,7 @@ RelationRegisterRelation(Relation relation)
|
|||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
if (oldcxt != (MemoryContext) CacheCxt)
|
|
||||||
elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
|
|
||||||
|
|
||||||
RelationInitLockInfo(relation);
|
RelationInitLockInfo(relation);
|
||||||
|
|
||||||
@ -1769,7 +1766,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
|
|||||||
if (newlyCreatedRelns == NULL)
|
if (newlyCreatedRelns == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
while (newlyCreatedRelns)
|
while (newlyCreatedRelns)
|
||||||
{
|
{
|
||||||
@ -1822,10 +1819,10 @@ RelationInitialize(void)
|
|||||||
* switch to cache memory context
|
* switch to cache memory context
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (!CacheCxt)
|
if (!CacheMemoryContext)
|
||||||
CacheCxt = CreateGlobalMemory("Cache");
|
CreateCacheMemoryContext();
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* create global caches
|
* create global caches
|
||||||
@ -2186,7 +2183,7 @@ RelationGetIndexList(Relation relation)
|
|||||||
heap_close(indrel, AccessShareLock);
|
heap_close(indrel, AccessShareLock);
|
||||||
|
|
||||||
/* Now save a copy of the completed list in the relcache entry. */
|
/* Now save a copy of the completed list in the relcache entry. */
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
relation->rd_indexlist = listCopy(result);
|
relation->rd_indexlist = listCopy(result);
|
||||||
relation->rd_indexfound = true;
|
relation->rd_indexfound = true;
|
||||||
MemoryContextSwitchTo(oldcxt);
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
8
src/backend/utils/cache/temprel.c
vendored
8
src/backend/utils/cache/temprel.c
vendored
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.24 2000/06/20 06:41:12 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.25 2000/06/28 03:32:25 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -67,7 +67,7 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
|
|||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
TempTable *temp_rel;
|
TempTable *temp_rel;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
temp_rel = (TempTable *) palloc(sizeof(TempTable));
|
temp_rel = (TempTable *) palloc(sizeof(TempTable));
|
||||||
temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
|
temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
|
||||||
@ -135,7 +135,7 @@ remove_temp_relation(Oid relid)
|
|||||||
List *l,
|
List *l,
|
||||||
*prev;
|
*prev;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
prev = NIL;
|
prev = NIL;
|
||||||
l = temp_rels;
|
l = temp_rels;
|
||||||
@ -185,7 +185,7 @@ invalidate_temp_relations(void)
|
|||||||
List *l,
|
List *l,
|
||||||
*prev;
|
*prev;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
|
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||||
|
|
||||||
prev = NIL;
|
prev = NIL;
|
||||||
l = temp_rels;
|
l = temp_rels;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.60 2000/06/04 15:06:29 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.61 2000/06/28 03:32:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -27,7 +27,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#ifdef ENABLE_SYSLOG
|
#ifdef ENABLE_SYSLOG
|
||||||
# include <syslog.h>
|
#include <syslog.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libpq/libpq.h"
|
#include "libpq/libpq.h"
|
||||||
@ -89,10 +89,9 @@ static int ElogDebugIndentLevel = 0;
|
|||||||
*--------------------
|
*--------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
elog(int lev, const char *fmt,...)
|
elog(int lev, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The expanded format and final output message are dynamically
|
* The expanded format and final output message are dynamically
|
||||||
* allocated if necessary, but not if they fit in the "reasonable
|
* allocated if necessary, but not if they fit in the "reasonable
|
||||||
@ -101,12 +100,21 @@ elog(int lev, const char *fmt,...)
|
|||||||
* working (since memory-clobber errors often take out malloc first).
|
* working (since memory-clobber errors often take out malloc first).
|
||||||
* Don't make these buffers unreasonably large though, on pain of
|
* Don't make these buffers unreasonably large though, on pain of
|
||||||
* having to chase a bug with no error message.
|
* having to chase a bug with no error message.
|
||||||
|
*
|
||||||
|
* Note that we use malloc() not palloc() because we want to retain
|
||||||
|
* control if we run out of memory. palloc() would recursively call
|
||||||
|
* elog(ERROR), which would be all right except if we are working on a
|
||||||
|
* FATAL or REALLYFATAL error. We'd lose track of the fatal condition
|
||||||
|
* and report a mere ERROR to outer loop, which would be a Bad Thing.
|
||||||
|
* So, we substitute an appropriate message in-place, without downgrading
|
||||||
|
* the level if it's above ERROR.
|
||||||
*/
|
*/
|
||||||
char fmt_fixedbuf[128];
|
char fmt_fixedbuf[128];
|
||||||
char msg_fixedbuf[256];
|
char msg_fixedbuf[256];
|
||||||
char *fmt_buf = fmt_fixedbuf;
|
char *fmt_buf = fmt_fixedbuf;
|
||||||
char *msg_buf = msg_fixedbuf;
|
char *msg_buf = msg_fixedbuf;
|
||||||
|
/* this buffer is only used for strange values of lev: */
|
||||||
|
char prefix_buf[32];
|
||||||
/* this buffer is only used if errno has a bogus value: */
|
/* this buffer is only used if errno has a bogus value: */
|
||||||
char errorstr_buf[32];
|
char errorstr_buf[32];
|
||||||
const char *errorstr;
|
const char *errorstr;
|
||||||
@ -115,7 +123,6 @@ elog(int lev, const char *fmt,...)
|
|||||||
char *bp;
|
char *bp;
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
int space_needed;
|
int space_needed;
|
||||||
|
|
||||||
int len;
|
int len;
|
||||||
/* size of the prefix needed for timestamp and pid, if enabled */
|
/* size of the prefix needed for timestamp and pid, if enabled */
|
||||||
size_t timestamp_size;
|
size_t timestamp_size;
|
||||||
@ -123,6 +130,15 @@ elog(int lev, const char *fmt,...)
|
|||||||
if (lev <= DEBUG && Debugfile < 0)
|
if (lev <= DEBUG && Debugfile < 0)
|
||||||
return; /* ignore debug msgs if noplace to send */
|
return; /* ignore debug msgs if noplace to send */
|
||||||
|
|
||||||
|
/* save errno string for %m */
|
||||||
|
if (errno < sys_nerr && errno >= 0)
|
||||||
|
errorstr = strerror(errno);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(errorstr_buf, "error %d", errno);
|
||||||
|
errorstr = errorstr_buf;
|
||||||
|
}
|
||||||
|
|
||||||
if (lev == ERROR || lev == FATAL)
|
if (lev == ERROR || lev == FATAL)
|
||||||
{
|
{
|
||||||
/* this is probably redundant... */
|
/* this is probably redundant... */
|
||||||
@ -156,21 +172,11 @@ elog(int lev, const char *fmt,...)
|
|||||||
prefix = "ERROR: ";
|
prefix = "ERROR: ";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* temporarily use msg buf for prefix */
|
sprintf(prefix_buf, "FATAL %d: ", lev);
|
||||||
sprintf(msg_fixedbuf, "FATAL %d: ", lev);
|
prefix = prefix_buf;
|
||||||
prefix = msg_fixedbuf;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get errno string for %m */
|
|
||||||
if (errno < sys_nerr && errno >= 0)
|
|
||||||
errorstr = strerror(errno);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(errorstr_buf, "error %d", errno);
|
|
||||||
errorstr = errorstr_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
timestamp_size = 0;
|
timestamp_size = 0;
|
||||||
if (Log_timestamp)
|
if (Log_timestamp)
|
||||||
timestamp_size += TIMESTAMP_SIZE;
|
timestamp_size += TIMESTAMP_SIZE;
|
||||||
@ -190,9 +196,13 @@ elog(int lev, const char *fmt,...)
|
|||||||
fmt_buf = (char *) malloc(space_needed);
|
fmt_buf = (char *) malloc(space_needed);
|
||||||
if (fmt_buf == NULL)
|
if (fmt_buf == NULL)
|
||||||
{
|
{
|
||||||
/* We're up against it, convert to fatal out-of-memory error */
|
/* We're up against it, convert to out-of-memory error */
|
||||||
fmt_buf = fmt_fixedbuf;
|
fmt_buf = fmt_fixedbuf;
|
||||||
lev = REALLYFATAL;
|
if (lev < FATAL)
|
||||||
|
{
|
||||||
|
lev = ERROR;
|
||||||
|
prefix = "ERROR: ";
|
||||||
|
}
|
||||||
fmt = "elog: out of memory"; /* this must fit in
|
fmt = "elog: out of memory"; /* this must fit in
|
||||||
* fmt_fixedbuf! */
|
* fmt_fixedbuf! */
|
||||||
}
|
}
|
||||||
@ -281,15 +291,20 @@ elog(int lev, const char *fmt,...)
|
|||||||
msg_buf = (char *) malloc(space_needed);
|
msg_buf = (char *) malloc(space_needed);
|
||||||
if (msg_buf == NULL)
|
if (msg_buf == NULL)
|
||||||
{
|
{
|
||||||
/* We're up against it, convert to fatal out-of-memory error */
|
/* We're up against it, convert to out-of-memory error */
|
||||||
msg_buf = msg_fixedbuf;
|
msg_buf = msg_fixedbuf;
|
||||||
lev = REALLYFATAL;
|
if (lev < FATAL)
|
||||||
|
{
|
||||||
|
lev = ERROR;
|
||||||
|
prefix = "ERROR: ";
|
||||||
|
}
|
||||||
msg_buf[0] = '\0';
|
msg_buf[0] = '\0';
|
||||||
if (Log_timestamp)
|
if (Log_timestamp)
|
||||||
strcat(msg_buf, print_timestamp());
|
strcat(msg_buf, print_timestamp());
|
||||||
if (Log_pid)
|
if (Log_pid)
|
||||||
strcat(msg_buf, print_pid());
|
strcat(msg_buf, print_pid());
|
||||||
strcat(msg_buf, "FATAL: elog: out of memory");
|
strcat(msg_buf, prefix);
|
||||||
|
strcat(msg_buf, "elog: out of memory");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.42 2000/06/15 04:10:29 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.43 2000/06/28 03:32:31 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -134,7 +134,7 @@ load_external_function(char *filename, char *funcname)
|
|||||||
file_scanner = (DynamicFileList *)
|
file_scanner = (DynamicFileList *)
|
||||||
malloc(sizeof(DynamicFileList) + strlen(filename));
|
malloc(sizeof(DynamicFileList) + strlen(filename));
|
||||||
if (file_scanner == NULL)
|
if (file_scanner == NULL)
|
||||||
elog(FATAL, "Out of memory in load_external_function");
|
elog(ERROR, "Out of memory in load_external_function");
|
||||||
|
|
||||||
MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
|
MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
|
||||||
strcpy(file_scanner->filename, filename);
|
strcpy(file_scanner->filename, filename);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.31 2000/04/12 17:16:00 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.32 2000/06/28 03:32:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -56,8 +56,7 @@
|
|||||||
/*
|
/*
|
||||||
* Private function prototypes
|
* Private function prototypes
|
||||||
*/
|
*/
|
||||||
static long *DynaHashAlloc(unsigned int size);
|
static void *DynaHashAlloc(Size size);
|
||||||
static void DynaHashFree(Pointer ptr);
|
|
||||||
static uint32 call_hash(HTAB *hashp, char *k);
|
static uint32 call_hash(HTAB *hashp, char *k);
|
||||||
static SEG_OFFSET seg_alloc(HTAB *hashp);
|
static SEG_OFFSET seg_alloc(HTAB *hashp);
|
||||||
static int bucket_alloc(HTAB *hashp);
|
static int bucket_alloc(HTAB *hashp);
|
||||||
@ -66,9 +65,7 @@ static int expand_table(HTAB *hashp);
|
|||||||
static int hdefault(HTAB *hashp);
|
static int hdefault(HTAB *hashp);
|
||||||
static int init_htab(HTAB *hashp, int nelem);
|
static int init_htab(HTAB *hashp, int nelem);
|
||||||
|
|
||||||
typedef long *((*dhalloc_ptr) ());
|
|
||||||
|
|
||||||
#ifndef FRONTEND
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* memory allocation routines
|
* memory allocation routines
|
||||||
*
|
*
|
||||||
@ -84,34 +81,24 @@ typedef long *((*dhalloc_ptr) ());
|
|||||||
* do the latter -cim 1/19/91
|
* do the latter -cim 1/19/91
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
|
static MemoryContext DynaHashCxt = NULL;
|
||||||
|
|
||||||
static long *
|
static void *
|
||||||
DynaHashAlloc(unsigned int size)
|
DynaHashAlloc(Size size)
|
||||||
{
|
{
|
||||||
if (!DynaHashCxt)
|
if (!DynaHashCxt)
|
||||||
DynaHashCxt = CreateGlobalMemory("DynaHash");
|
DynaHashCxt = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
"DynaHash",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
return (long *)
|
return MemoryContextAlloc(DynaHashCxt, size);
|
||||||
MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
DynaHashFree(Pointer ptr)
|
|
||||||
{
|
|
||||||
MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MEM_ALLOC DynaHashAlloc
|
#define MEM_ALLOC DynaHashAlloc
|
||||||
#define MEM_FREE DynaHashFree
|
|
||||||
|
|
||||||
#else /* FRONTEND */
|
|
||||||
|
|
||||||
#define MEM_ALLOC palloc
|
|
||||||
#define MEM_FREE pfree
|
#define MEM_FREE pfree
|
||||||
|
|
||||||
#endif /* FRONTEND */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pointer access macros. Shared memory implementation cannot
|
* pointer access macros. Shared memory implementation cannot
|
||||||
@ -147,7 +134,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
|
|||||||
HTAB *hashp;
|
HTAB *hashp;
|
||||||
|
|
||||||
|
|
||||||
hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
|
hashp = (HTAB *) MEM_ALLOC(sizeof(HTAB));
|
||||||
MemSet(hashp, 0, sizeof(HTAB));
|
MemSet(hashp, 0, sizeof(HTAB));
|
||||||
|
|
||||||
if (flags & HASH_FUNCTION)
|
if (flags & HASH_FUNCTION)
|
||||||
@ -181,7 +168,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
|
|||||||
/* setup hash table defaults */
|
/* setup hash table defaults */
|
||||||
|
|
||||||
hashp->hctl = NULL;
|
hashp->hctl = NULL;
|
||||||
hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
|
hashp->alloc = MEM_ALLOC;
|
||||||
hashp->dir = NULL;
|
hashp->dir = NULL;
|
||||||
hashp->segbase = NULL;
|
hashp->segbase = NULL;
|
||||||
|
|
||||||
@ -189,7 +176,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
|
|||||||
|
|
||||||
if (!hashp->hctl)
|
if (!hashp->hctl)
|
||||||
{
|
{
|
||||||
hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
|
hashp->hctl = (HHDR *) hashp->alloc(sizeof(HHDR));
|
||||||
if (!hashp->hctl)
|
if (!hashp->hctl)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -318,7 +305,8 @@ init_htab(HTAB *hashp, int nelem)
|
|||||||
/* Allocate a directory */
|
/* Allocate a directory */
|
||||||
if (!(hashp->dir))
|
if (!(hashp->dir))
|
||||||
{
|
{
|
||||||
hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
|
hashp->dir = (SEG_OFFSET *)
|
||||||
|
hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
|
||||||
if (!hashp->dir)
|
if (!hashp->dir)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -445,7 +433,7 @@ hash_destroy(HTAB *hashp)
|
|||||||
/* cannot destroy a shared memory hash table */
|
/* cannot destroy a shared memory hash table */
|
||||||
Assert(!hashp->segbase);
|
Assert(!hashp->segbase);
|
||||||
/* allocation method must be one we know how to free, too */
|
/* allocation method must be one we know how to free, too */
|
||||||
Assert(hashp->alloc == (dhalloc_ptr) MEM_ALLOC);
|
Assert(hashp->alloc == MEM_ALLOC);
|
||||||
|
|
||||||
hash_stats("destroy", hashp);
|
hash_stats("destroy", hashp);
|
||||||
|
|
||||||
@ -885,7 +873,7 @@ dir_realloc(HTAB *hashp)
|
|||||||
new_dirsize = new_dsize * sizeof(SEG_OFFSET);
|
new_dirsize = new_dsize * sizeof(SEG_OFFSET);
|
||||||
|
|
||||||
old_p = (char *) hashp->dir;
|
old_p = (char *) hashp->dir;
|
||||||
p = (char *) hashp->alloc((unsigned long) new_dirsize);
|
p = (char *) hashp->alloc((Size) new_dirsize);
|
||||||
|
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
{
|
{
|
||||||
@ -906,8 +894,7 @@ seg_alloc(HTAB *hashp)
|
|||||||
SEGMENT segp;
|
SEGMENT segp;
|
||||||
SEG_OFFSET segOffset;
|
SEG_OFFSET segOffset;
|
||||||
|
|
||||||
segp = (SEGMENT) hashp->alloc((unsigned long)
|
segp = (SEGMENT) hashp->alloc(sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
|
||||||
sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
|
|
||||||
|
|
||||||
if (!segp)
|
if (!segp)
|
||||||
return 0;
|
return 0;
|
||||||
@ -937,8 +924,7 @@ bucket_alloc(HTAB *hashp)
|
|||||||
/* make sure its aligned correctly */
|
/* make sure its aligned correctly */
|
||||||
bucketSize = MAXALIGN(bucketSize);
|
bucketSize = MAXALIGN(bucketSize);
|
||||||
|
|
||||||
tmpBucket = (ELEMENT *)
|
tmpBucket = (ELEMENT *) hashp->alloc(BUCKET_ALLOC_INCR * bucketSize);
|
||||||
hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
|
|
||||||
|
|
||||||
if (!tmpBucket)
|
if (!tmpBucket)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
# Makefile for utils/init
|
# Makefile for utils/init
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.13 2000/05/29 05:45:32 tgl Exp $
|
# $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.14 2000/06/28 03:32:43 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
SRCDIR = ../../..
|
SRCDIR = ../../..
|
||||||
include ../../../Makefile.global
|
include ../../../Makefile.global
|
||||||
|
|
||||||
OBJS = enbl.o findbe.o globals.o miscinit.o postinit.o
|
OBJS = findbe.o globals.o miscinit.o postinit.o
|
||||||
|
|
||||||
all: SUBSYS.o
|
all: SUBSYS.o
|
||||||
|
|
||||||
@ -27,4 +27,3 @@ clean:
|
|||||||
ifeq (depend,$(wildcard depend))
|
ifeq (depend,$(wildcard depend))
|
||||||
include depend
|
include depend
|
||||||
endif
|
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
|
* 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"
|
#include "mb/pg_wchar.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void BaseInit(void);
|
|
||||||
|
|
||||||
static void ReverifyMyDatabase(const char *name);
|
static void ReverifyMyDatabase(const char *name);
|
||||||
static void InitCommunication(void);
|
static void InitCommunication(void);
|
||||||
|
|
||||||
@ -222,8 +220,6 @@ InitCommunication()
|
|||||||
* Be very careful with the order of calls in the InitPostgres function.
|
* Be very careful with the order of calls in the InitPostgres function.
|
||||||
* --------------------------------
|
* --------------------------------
|
||||||
*/
|
*/
|
||||||
extern int NBuffers;
|
|
||||||
|
|
||||||
int lockingOff = 0; /* backend -L switch */
|
int lockingOff = 0; /* backend -L switch */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -405,21 +401,6 @@ InitPostgres(const char *dbname)
|
|||||||
void
|
void
|
||||||
BaseInit(void)
|
BaseInit(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
|
||||||
* Turn on the exception handler. Note: we cannot use elog, Assert,
|
|
||||||
* AssertState, etc. until after exception handling is on.
|
|
||||||
*/
|
|
||||||
EnableExceptionHandling(true);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory system initialization - we may call palloc after
|
|
||||||
* EnableMemoryContext()). Note that EnableMemoryContext() must
|
|
||||||
* happen before EnablePortalManager().
|
|
||||||
*/
|
|
||||||
EnableMemoryContext(true); /* initializes the "top context" */
|
|
||||||
EnablePortalManager(true); /* memory for portal/transaction stuff */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attach to shared memory and semaphores, and initialize our
|
* Attach to shared memory and semaphores, and initialize our
|
||||||
* input/output/debugging file descriptors.
|
* input/output/debugging file descriptors.
|
||||||
@ -427,4 +408,6 @@ BaseInit(void)
|
|||||||
InitCommunication();
|
InitCommunication();
|
||||||
DebugFileOpen();
|
DebugFileOpen();
|
||||||
smgrinit();
|
smgrinit();
|
||||||
|
|
||||||
|
EnablePortalManager(); /* memory for portal/transaction stuff */
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* WIN1250 client encoding support contributed by Pavel Behal
|
* WIN1250 client encoding support contributed by Pavel Behal
|
||||||
* SJIS UDC (NEC selection IBM kanji) support contributed by Eiji Tokuya
|
* SJIS UDC (NEC selection IBM kanji) support contributed by Eiji Tokuya
|
||||||
*
|
*
|
||||||
* $Id: conv.c,v 1.15 2000/05/20 13:12:26 ishii Exp $
|
* $Id: conv.c,v 1.16 2000/06/28 03:32:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -1521,7 +1521,8 @@ pg_encoding_conv_tbl pg_conv_tbl[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DEBUGMAIN
|
#ifdef DEBUGMAIN
|
||||||
#include "utils/mcxt.h"
|
#include "postgres.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
/*
|
/*
|
||||||
* testing for sjis2mic() and mic2sjis()
|
* testing for sjis2mic() and mic2sjis()
|
||||||
*/
|
*/
|
||||||
@ -1565,21 +1566,23 @@ main()
|
|||||||
void
|
void
|
||||||
elog(int lev, const char *fmt,...)
|
elog(int lev, const char *fmt,...)
|
||||||
{
|
{
|
||||||
};
|
}
|
||||||
|
|
||||||
MemoryContext CurrentMemoryContext;
|
MemoryContext CurrentMemoryContext;
|
||||||
Pointer
|
|
||||||
|
void *
|
||||||
MemoryContextAlloc(MemoryContext context, Size size)
|
MemoryContextAlloc(MemoryContext context, Size size)
|
||||||
{
|
{
|
||||||
};
|
}
|
||||||
Pointer
|
|
||||||
MemoryContextRealloc(MemoryContext context,
|
|
||||||
Pointer pointer,
|
|
||||||
Size size)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
void
|
void
|
||||||
MemoryContextFree(MemoryContext context, Pointer pointer)
|
pfree(void *pointer)
|
||||||
{
|
{
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
repalloc(void *pointer, Size size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
# Makefile for utils/mmgr
|
# Makefile for utils/mmgr
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.8 2000/05/29 05:45:40 tgl Exp $
|
# $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.9 2000/06/28 03:32:50 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
SRCDIR = ../../..
|
SRCDIR = ../../..
|
||||||
include ../../../Makefile.global
|
include ../../../Makefile.global
|
||||||
|
|
||||||
OBJS = aset.o mcxt.o palloc.o portalmem.o oset.o
|
OBJS = aset.o mcxt.o portalmem.o
|
||||||
|
|
||||||
all: SUBSYS.o
|
all: SUBSYS.o
|
||||||
|
|
||||||
|
379
src/backend/utils/mmgr/README
Normal file
379
src/backend/utils/mmgr/README
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
Proposal for memory allocation fixes, take 2 21-Jun-2000
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
We know that Postgres has serious problems with memory leakage during
|
||||||
|
large queries that process a lot of pass-by-reference data. There is
|
||||||
|
no provision for recycling memory until end of query. This needs to be
|
||||||
|
fixed, even more so with the advent of TOAST which will allow very large
|
||||||
|
chunks of data to be passed around in the system. So, here is a proposal.
|
||||||
|
|
||||||
|
|
||||||
|
Background
|
||||||
|
----------
|
||||||
|
|
||||||
|
We already do most of our memory allocation in "memory contexts", which
|
||||||
|
are usually AllocSets as implemented by backend/utils/mmgr/aset.c. What
|
||||||
|
we need to do is create more contexts and define proper rules about when
|
||||||
|
they can be freed.
|
||||||
|
|
||||||
|
The basic operations on a memory context are:
|
||||||
|
|
||||||
|
* create a context
|
||||||
|
|
||||||
|
* allocate a chunk of memory within a context (equivalent of standard
|
||||||
|
C library's malloc())
|
||||||
|
|
||||||
|
* delete a context (including freeing all the memory allocated therein)
|
||||||
|
|
||||||
|
* reset a context (free all memory allocated in the context, but not the
|
||||||
|
context object itself)
|
||||||
|
|
||||||
|
Given a chunk of memory previously allocated from a context, one can
|
||||||
|
free it or reallocate it larger or smaller (corresponding to standard
|
||||||
|
library's free() and realloc() routines). These operations return memory
|
||||||
|
to or get more memory from the same context the chunk was originally
|
||||||
|
allocated in.
|
||||||
|
|
||||||
|
At all times there is a "current" context denoted by the
|
||||||
|
CurrentMemoryContext global variable. The backend macro palloc()
|
||||||
|
implicitly allocates space in that context. The MemoryContextSwitchTo()
|
||||||
|
operation selects a new current context (and returns the previous context,
|
||||||
|
so that the caller can restore the previous context before exiting).
|
||||||
|
|
||||||
|
The main advantage of memory contexts over plain use of malloc/free is
|
||||||
|
that the entire contents of a memory context can be freed easily, without
|
||||||
|
having to request freeing of each individual chunk within it. This is
|
||||||
|
both faster and more reliable than per-chunk bookkeeping. We already use
|
||||||
|
this fact to clean up at transaction end: by resetting all the active
|
||||||
|
contexts, we reclaim all memory. What we need are additional contexts
|
||||||
|
that can be reset or deleted at strategic times within a query, such as
|
||||||
|
after each tuple.
|
||||||
|
|
||||||
|
|
||||||
|
pfree/repalloc no longer depend on CurrentMemoryContext
|
||||||
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
In this proposal, pfree() and repalloc() can be applied to any chunk
|
||||||
|
whether it belongs to CurrentMemoryContext or not --- the chunk's owning
|
||||||
|
context will be invoked to handle the operation, regardless. This is a
|
||||||
|
change from the old requirement that CurrentMemoryContext must be set
|
||||||
|
to the same context the memory was allocated from before one can use
|
||||||
|
pfree() or repalloc(). The old coding requirement is obviously fairly
|
||||||
|
error-prone, and will become more so the more context-switching we do;
|
||||||
|
so I think it's essential to use CurrentMemoryContext only for palloc.
|
||||||
|
We can avoid needing it for pfree/repalloc by putting restrictions on
|
||||||
|
context managers as discussed below.
|
||||||
|
|
||||||
|
We could even consider getting rid of CurrentMemoryContext entirely,
|
||||||
|
instead requiring the target memory context for allocation to be specified
|
||||||
|
explicitly. But I think that would be too much notational overhead ---
|
||||||
|
we'd have to pass an apppropriate memory context to called routines in
|
||||||
|
many places. For example, the copyObject routines would need to be passed
|
||||||
|
a context, as would function execution routines that return a
|
||||||
|
pass-by-reference datatype. And what of routines that temporarily
|
||||||
|
allocate space internally, but don't return it to their caller? We
|
||||||
|
certainly don't want to clutter every call in the system with "here is
|
||||||
|
a context to use for any temporary memory allocation you might want to
|
||||||
|
do". So there'd still need to be a global variable specifying a suitable
|
||||||
|
temporary-allocation context. That might as well be CurrentMemoryContext.
|
||||||
|
|
||||||
|
|
||||||
|
Additions to the memory-context mechanism
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
If we are going to have more contexts, we need more mechanism for keeping
|
||||||
|
track of them; else we risk leaking whole contexts under error conditions.
|
||||||
|
|
||||||
|
We can do this by creating trees of "parent" and "child" contexts. When
|
||||||
|
creating a memory context, the new context can be specified to be a child
|
||||||
|
of some existing context. A context can have many children, but only one
|
||||||
|
parent. In this way the contexts form a forest (not necessarily a single
|
||||||
|
tree, since there could be more than one top-level context).
|
||||||
|
|
||||||
|
We then say that resetting or deleting any particular context resets or
|
||||||
|
deletes all its direct and indirect children as well. This feature allows
|
||||||
|
us to manage a lot of contexts without fear that some will be leaked; we
|
||||||
|
only need to keep track of one top-level context that we are going to
|
||||||
|
delete at transaction end, and make sure that any shorter-lived contexts
|
||||||
|
we create are descendants of that context. Since the tree can have
|
||||||
|
multiple levels, we can deal easily with nested lifetimes of storage,
|
||||||
|
such as per-transaction, per-statement, per-scan, per-tuple. Storage
|
||||||
|
lifetimes that only partially overlap can be handled by allocating
|
||||||
|
from different trees of the context forest (there are some examples
|
||||||
|
in the next section).
|
||||||
|
|
||||||
|
For convenience we will also want operations like "reset/delete all
|
||||||
|
children of a given context, but don't reset or delete that context
|
||||||
|
itself".
|
||||||
|
|
||||||
|
|
||||||
|
Top-level contexts
|
||||||
|
------------------
|
||||||
|
|
||||||
|
There will be several top-level contexts --- these contexts have no parent
|
||||||
|
and will be referenced by global variables. At any instant the system may
|
||||||
|
contain many additional contexts, but all other contexts should be direct
|
||||||
|
or indirect children of one of the top-level contexts to ensure they are
|
||||||
|
not leaked in event of an error. I presently envision these top-level
|
||||||
|
contexts:
|
||||||
|
|
||||||
|
TopMemoryContext --- allocating here is essentially the same as "malloc",
|
||||||
|
because this context will never be reset or deleted. This is for stuff
|
||||||
|
that should live forever, or for stuff that you know you will delete
|
||||||
|
at the appropriate time. An example is fd.c's tables of open files,
|
||||||
|
as well as the context management nodes for memory contexts themselves.
|
||||||
|
Avoid allocating stuff here unless really necessary, and especially
|
||||||
|
avoid running with CurrentMemoryContext pointing here.
|
||||||
|
|
||||||
|
PostmasterContext --- this is the postmaster's normal working context.
|
||||||
|
After a backend is spawned, it can delete PostmasterContext to free its
|
||||||
|
copy of memory the postmaster was using that it doesn't need. (Anything
|
||||||
|
that has to be passed from postmaster to backends will be passed in
|
||||||
|
TopMemoryContext. The postmaster will probably have only TopMemoryContext,
|
||||||
|
PostmasterContext, and possibly ErrorContext --- the remaining top-level
|
||||||
|
contexts will be set up in each backend during startup.)
|
||||||
|
|
||||||
|
CacheMemoryContext --- permanent storage for relcache, catcache, and
|
||||||
|
related modules. This will never be reset or deleted, either, so it's
|
||||||
|
not truly necessary to distinguish it from TopMemoryContext. But it
|
||||||
|
seems worthwhile to maintain the distinction for debugging purposes.
|
||||||
|
(Note: CacheMemoryContext may well have child-contexts with shorter
|
||||||
|
lifespans. For example, a child context seems like the best place to
|
||||||
|
keep the subsidiary storage associated with a relcache entry; that way
|
||||||
|
we can free rule parsetrees and so forth easily, without having to depend
|
||||||
|
on constructing a reliable version of freeObject().)
|
||||||
|
|
||||||
|
QueryContext --- this is where the storage holding a received query string
|
||||||
|
is kept, as well as storage that should live as long as the query string,
|
||||||
|
notably the parsetree constructed from it. This context will be reset at
|
||||||
|
the top of each cycle of the outer loop of PostgresMain, thereby freeing
|
||||||
|
the old query and parsetree. We must keep this separate from
|
||||||
|
TopTransactionContext because a query string might need to live either a
|
||||||
|
longer or shorter time than a transaction, depending on whether it
|
||||||
|
contains begin/end commands or not. (This'll also fix the nasty bug that
|
||||||
|
"vacuum; anything else" crashes if submitted as a single query string,
|
||||||
|
because vacuum's xact commit frees the memory holding the parsetree...)
|
||||||
|
|
||||||
|
TopTransactionContext --- this holds everything that lives until end of
|
||||||
|
transaction (longer than one statement within a transaction!). An example
|
||||||
|
of what has to be here is the list of pending NOTIFY messages to be sent
|
||||||
|
at xact commit. This context will be reset, and all its children deleted,
|
||||||
|
at conclusion of each transaction cycle. Note: presently I envision that
|
||||||
|
this context will NOT be cleared immediately upon error; its contents
|
||||||
|
will survive anyway until the transaction block is exited by
|
||||||
|
COMMIT/ROLLBACK. This seems appropriate since we want to move in the
|
||||||
|
direction of allowing a transaction to continue processing after an error.
|
||||||
|
|
||||||
|
TransactionCommandContext --- this is really a child of
|
||||||
|
TopTransactionContext, not a top-level context, but we'll probably store a
|
||||||
|
link to it in a global variable anyway for convenience. All the memory
|
||||||
|
allocated during planning and execution lives here or in a child context.
|
||||||
|
This context is deleted at statement completion, whether normal completion
|
||||||
|
or error abort.
|
||||||
|
|
||||||
|
ErrorContext --- this permanent context will be switched into
|
||||||
|
for error recovery processing, and then reset on completion of recovery.
|
||||||
|
We'll arrange to have, say, 8K of memory available in it at all times.
|
||||||
|
In this way, we can ensure that some memory is available for error
|
||||||
|
recovery even if the backend has run out of memory otherwise. This should
|
||||||
|
allow out-of-memory to be treated as a normal ERROR condition, not a FATAL
|
||||||
|
error.
|
||||||
|
|
||||||
|
If we ever implement nested transactions, there may need to be some
|
||||||
|
additional levels of transaction-local contexts between
|
||||||
|
TopTransactionContext and TransactionCommandContext, but that's beyond
|
||||||
|
the scope of this proposal.
|
||||||
|
|
||||||
|
|
||||||
|
Transient contexts during execution
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
The planner will probably have a transient context in which it stores
|
||||||
|
pathnodes; this will allow it to release the bulk of its temporary space
|
||||||
|
usage (which can be a lot, for large joins) at completion of planning.
|
||||||
|
The completed plan tree will be in TransactionCommandContext.
|
||||||
|
|
||||||
|
The executor will have contexts with lifetime similar to plan nodes
|
||||||
|
(I'm not sure at the moment whether there's need for one such context
|
||||||
|
per plan level, or whether a single context is sufficient). These
|
||||||
|
contexts will hold plan-node-local execution state and related items.
|
||||||
|
There will also be a context on each plan level that is reset at the start
|
||||||
|
of each tuple processing cycle. This per-tuple context will be the normal
|
||||||
|
CurrentMemoryContext during evaluation of expressions and so forth. By
|
||||||
|
resetting it, we reclaim transient memory that was used during processing
|
||||||
|
of the prior tuple. That should be enough to solve the problem of running
|
||||||
|
out of memory on large queries. We must have a per-tuple context in each
|
||||||
|
plan node, and we must reset it at the start of a tuple cycle rather than
|
||||||
|
the end, so that each plan node can use results of expression evaluation
|
||||||
|
as part of the tuple it returns to its parent node.
|
||||||
|
|
||||||
|
By resetting the per-tuple context, we will be able to free memory after
|
||||||
|
each tuple is processed, rather than only after the whole plan is
|
||||||
|
processed. This should solve our memory leakage problems pretty well;
|
||||||
|
yet we do not need to add very much new bookkeeping logic to do it.
|
||||||
|
In particular, we do *not* need to try to keep track of individual values
|
||||||
|
palloc'd during expression evaluation.
|
||||||
|
|
||||||
|
Note we assume that resetting a context is a cheap operation. This is
|
||||||
|
true already, and we can make it even more true with a little bit of
|
||||||
|
tuning in aset.c.
|
||||||
|
|
||||||
|
There will be some special cases, such as aggregate functions. nodeAgg.c
|
||||||
|
needs to remember the results of evaluation of aggregate transition
|
||||||
|
functions from one tuple cycle to the next, so it can't just discard
|
||||||
|
all per-tuple state in each cycle. The easiest way to handle this seems
|
||||||
|
to be to have two per-tuple contexts in an aggregate node, and to
|
||||||
|
ping-pong between them, so that at each tuple one is the active allocation
|
||||||
|
context and the other holds any results allocated by the prior cycle's
|
||||||
|
transition function.
|
||||||
|
|
||||||
|
Executor routines that switch the active CurrentMemoryContext may need
|
||||||
|
to copy data into their caller's current memory context before returning.
|
||||||
|
I think there will be relatively little need for that, because of the
|
||||||
|
convention of resetting the per-tuple context at the *start* of an
|
||||||
|
execution cycle rather than at its end. With that rule, an execution
|
||||||
|
node can return a tuple that is palloc'd in its per-tuple context, and
|
||||||
|
the tuple will remain good until the node is called for another tuple
|
||||||
|
or told to end execution. This is pretty much the same state of affairs
|
||||||
|
that exists now, since a scan node can return a direct pointer to a tuple
|
||||||
|
in a disk buffer that is only guaranteed to remain good that long.
|
||||||
|
|
||||||
|
A more common reason for copying data will be to transfer a result from
|
||||||
|
per-tuple context to per-run context; for example, a Unique node will
|
||||||
|
save the last distinct tuple value in its per-run context, requiring a
|
||||||
|
copy step. (Actually, Unique could use the same trick with two per-tuple
|
||||||
|
contexts as described above for Agg, but there will probably be other
|
||||||
|
cases where doing an extra copy step is the right thing.)
|
||||||
|
|
||||||
|
Another interesting special case is VACUUM, which needs to allocate
|
||||||
|
working space that will survive its forced transaction commits, yet
|
||||||
|
be released on error. Currently it does that through a "portal",
|
||||||
|
which is essentially a child context of TopMemoryContext. While that
|
||||||
|
way still works, it's ugly since xact abort needs special processing
|
||||||
|
to delete the portal. Better would be to use a context that's a child
|
||||||
|
of QueryContext and hence is certain to go away as part of normal
|
||||||
|
processing. (Eventually we might have an even better solution from
|
||||||
|
nested transactions, but this'll do fine for now.)
|
||||||
|
|
||||||
|
|
||||||
|
Mechanisms to allow multiple types of contexts
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
We may want several different types of memory contexts with different
|
||||||
|
allocation policies but similar external behavior. To handle this,
|
||||||
|
memory allocation functions will be accessed via function pointers,
|
||||||
|
and we will require all context types to obey the conventions given here.
|
||||||
|
(This is not very far different from the existing code.)
|
||||||
|
|
||||||
|
A memory context will be represented by an object like
|
||||||
|
|
||||||
|
typedef struct MemoryContextData
|
||||||
|
{
|
||||||
|
NodeTag type; /* identifies exact kind of context */
|
||||||
|
MemoryContextMethods methods;
|
||||||
|
MemoryContextData *parent; /* NULL if no parent (toplevel context) */
|
||||||
|
MemoryContextData *firstchild; /* head of linked list of children */
|
||||||
|
MemoryContextData *nextchild; /* next child of same parent */
|
||||||
|
char *name; /* context name (just for debugging) */
|
||||||
|
} MemoryContextData, *MemoryContext;
|
||||||
|
|
||||||
|
This is essentially an abstract superclass, and the "methods" pointer is
|
||||||
|
its virtual function table. Specific memory context types will use
|
||||||
|
derived structs having these fields as their first fields. All the
|
||||||
|
contexts of a specific type will have methods pointers that point to the
|
||||||
|
same static table of function pointers, which will look like
|
||||||
|
|
||||||
|
typedef struct MemoryContextMethodsData
|
||||||
|
{
|
||||||
|
Pointer (*alloc) (MemoryContext c, Size size);
|
||||||
|
void (*free_p) (Pointer chunk);
|
||||||
|
Pointer (*realloc) (Pointer chunk, Size newsize);
|
||||||
|
void (*reset) (MemoryContext c);
|
||||||
|
void (*delete) (MemoryContext c);
|
||||||
|
} MemoryContextMethodsData, *MemoryContextMethods;
|
||||||
|
|
||||||
|
Alloc, reset, and delete requests will take a MemoryContext pointer
|
||||||
|
as parameter, so they'll have no trouble finding the method pointer
|
||||||
|
to call. Free and realloc are trickier. To make those work, we will
|
||||||
|
require all memory context types to produce allocated chunks that
|
||||||
|
are immediately preceded by a standard chunk header, which has the
|
||||||
|
layout
|
||||||
|
|
||||||
|
typedef struct StandardChunkHeader
|
||||||
|
{
|
||||||
|
MemoryContext mycontext; /* Link to owning context object */
|
||||||
|
Size size; /* Allocated size of chunk */
|
||||||
|
};
|
||||||
|
|
||||||
|
It turns out that the existing aset.c memory context type does this
|
||||||
|
already, and probably any other kind of context would need to have the
|
||||||
|
same data available to support realloc, so this is not really creating
|
||||||
|
any additional overhead. (Note that if a context type needs more per-
|
||||||
|
allocated-chunk information than this, it can make an additional
|
||||||
|
nonstandard header that precedes the standard header. So we're not
|
||||||
|
constraining context-type designers very much.)
|
||||||
|
|
||||||
|
Given this, the pfree routine will look something like
|
||||||
|
|
||||||
|
StandardChunkHeader * header =
|
||||||
|
(StandardChunkHeader *) ((char *) p - sizeof(StandardChunkHeader));
|
||||||
|
|
||||||
|
(*header->mycontext->methods->free_p) (p);
|
||||||
|
|
||||||
|
We could do it as a macro, but the macro would have to evaluate its
|
||||||
|
argument twice, which seems like a bad idea (the current pfree macro
|
||||||
|
does not do that). This is already saving two levels of function call
|
||||||
|
compared to the existing code, so I think we're doing fine without
|
||||||
|
squeezing out that last little bit ...
|
||||||
|
|
||||||
|
|
||||||
|
More control over aset.c behavior
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Currently, aset.c allocates an 8K block upon the first allocation in
|
||||||
|
a context, and doubles that size for each successive block request.
|
||||||
|
That's good behavior for a context that might hold *lots* of data, and
|
||||||
|
the overhead wasn't bad when we had only a few contexts in existence.
|
||||||
|
With dozens if not hundreds of smaller contexts in the system, we will
|
||||||
|
want to be able to fine-tune things a little better.
|
||||||
|
|
||||||
|
The creator of a context will be able to specify an initial block size
|
||||||
|
and a maximum block size. Selecting smaller values will prevent wastage
|
||||||
|
of space in contexts that aren't expected to hold very much (an example is
|
||||||
|
the relcache's per-relation contexts).
|
||||||
|
|
||||||
|
Also, it will be possible to specify a minimum context size. If this
|
||||||
|
value is greater than zero then a block of that size will be grabbed
|
||||||
|
immediately upon context creation, and cleared but not released during
|
||||||
|
context resets. This feature is needed for ErrorContext (see above).
|
||||||
|
It is also useful for per-tuple contexts, which will be reset frequently
|
||||||
|
and typically will not allocate very much space per tuple cycle. We can
|
||||||
|
save a lot of unnecessary malloc traffic if these contexts hang onto one
|
||||||
|
allocation block rather than releasing and reacquiring the block on
|
||||||
|
each tuple cycle.
|
||||||
|
|
||||||
|
|
||||||
|
Other notes
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The original version of this proposal suggested that functions returning
|
||||||
|
pass-by-reference datatypes should be required to return a value freshly
|
||||||
|
palloc'd in their caller's memory context, never a pointer to an input
|
||||||
|
value. I've abandoned that notion since it clearly is prone to error.
|
||||||
|
In the current proposal, it is possible to discover which context a
|
||||||
|
chunk of memory is allocated in (by checking the required standard chunk
|
||||||
|
header), so nodeAgg can determine whether or not it's safe to reset
|
||||||
|
its working context; it doesn't have to rely on the transition function
|
||||||
|
to do what it's expecting.
|
||||||
|
|
||||||
|
It might be that the executor per-run contexts described above should
|
||||||
|
be tied directly to executor "EState" nodes, that is, one context per
|
||||||
|
EState. I'm not real clear on the lifespan of EStates or the situations
|
||||||
|
where we have just one or more than one, so I'm not sure. Comments?
|
||||||
|
|
||||||
|
It would probably be possible to adapt the existing "portal" memory
|
||||||
|
management mechanism to do what we need. I am instead proposing setting
|
||||||
|
up a totally new mechanism, because the portal code strikes me as
|
||||||
|
extremely crufty and unwieldy. It may be that we can eventually remove
|
||||||
|
portals entirely, or perhaps reimplement them with this mechanism
|
||||||
|
underneath.
|
@ -3,12 +3,15 @@
|
|||||||
* aset.c
|
* aset.c
|
||||||
* Allocation set definitions.
|
* Allocation set definitions.
|
||||||
*
|
*
|
||||||
|
* AllocSet is our standard implementation of the abstract MemoryContext
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
*
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.27 2000/05/21 02:23:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.28 2000/06/28 03:32:50 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTE:
|
* NOTE:
|
||||||
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
* This is a new (Feb. 05, 1999) implementation of the allocation set
|
||||||
@ -30,15 +33,68 @@
|
|||||||
* AllocSetReset() under the old way.
|
* AllocSetReset() under the old way.
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
#undef AllocSetReset
|
/*
|
||||||
#undef malloc
|
* AllocSetContext is defined in nodes/memnodes.h.
|
||||||
#undef free
|
*/
|
||||||
#undef realloc
|
typedef AllocSetContext *AllocSet;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AllocPointer
|
||||||
|
* Aligned pointer which may be a member of an allocation set.
|
||||||
|
*/
|
||||||
|
typedef void *AllocPointer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AllocBlock
|
||||||
|
* An AllocBlock is the unit of memory that is obtained by aset.c
|
||||||
|
* from malloc(). It contains one or more AllocChunks, which are
|
||||||
|
* the units requested by palloc() and freed by pfree(). AllocChunks
|
||||||
|
* cannot be returned to malloc() individually, instead they are put
|
||||||
|
* on freelists by pfree() and re-used by the next palloc() that has
|
||||||
|
* a matching request size.
|
||||||
|
*
|
||||||
|
* AllocBlockData is the header data for a block --- the usable space
|
||||||
|
* within the block begins at the next alignment boundary.
|
||||||
|
*/
|
||||||
|
typedef struct AllocBlockData
|
||||||
|
{
|
||||||
|
AllocSet aset; /* aset that owns this block */
|
||||||
|
AllocBlock next; /* next block in aset's blocks list */
|
||||||
|
char *freeptr; /* start of free space in this block */
|
||||||
|
char *endptr; /* end of space in this block */
|
||||||
|
} AllocBlockData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AllocChunk
|
||||||
|
* The prefix of each piece of memory in an AllocBlock
|
||||||
|
*
|
||||||
|
* NB: this MUST match StandardChunkHeader as defined by utils/memutils.h.
|
||||||
|
*/
|
||||||
|
typedef struct AllocChunkData
|
||||||
|
{
|
||||||
|
/* aset is the owning aset if allocated, or the freelist link if free */
|
||||||
|
void *aset;
|
||||||
|
/* size is always the size of the usable space in the chunk */
|
||||||
|
Size size;
|
||||||
|
} AllocChunkData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AllocPointerIsValid
|
||||||
|
* True iff pointer is valid allocation pointer.
|
||||||
|
*/
|
||||||
|
#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AllocSetIsValid
|
||||||
|
* True iff set is valid allocation set.
|
||||||
|
*/
|
||||||
|
#define AllocSetIsValid(set) PointerIsValid(set)
|
||||||
|
|
||||||
/*--------------------
|
/*--------------------
|
||||||
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
|
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
|
||||||
@ -59,9 +115,9 @@
|
|||||||
/* Size of largest chunk that we use a fixed size for */
|
/* Size of largest chunk that we use a fixed size for */
|
||||||
|
|
||||||
/*--------------------
|
/*--------------------
|
||||||
* The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
|
* The first block allocated for an allocset has size initBlockSize.
|
||||||
* Each time we have to allocate another block, we double the block size
|
* Each time we have to allocate another block, we double the block size
|
||||||
* (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
|
* (if possible, and without exceeding maxBlockSize), so as to reduce
|
||||||
* the bookkeeping load on malloc().
|
* the bookkeeping load on malloc().
|
||||||
*
|
*
|
||||||
* Blocks allocated to hold oversize chunks do not follow this rule, however;
|
* Blocks allocated to hold oversize chunks do not follow this rule, however;
|
||||||
@ -74,20 +130,21 @@
|
|||||||
* AllocSetAlloc has discretion whether to put the request into an existing
|
* AllocSetAlloc has discretion whether to put the request into an existing
|
||||||
* block or make a single-chunk block.
|
* block or make a single-chunk block.
|
||||||
*
|
*
|
||||||
* We must have ALLOC_MIN_BLOCK_SIZE > ALLOC_SMALLCHUNK_LIMIT and
|
* We must have initBlockSize > ALLOC_SMALLCHUNK_LIMIT and
|
||||||
* ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
|
* ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
|
||||||
*--------------------
|
*--------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define ALLOC_MIN_BLOCK_SIZE (8 * 1024)
|
|
||||||
#define ALLOC_MAX_BLOCK_SIZE (8 * 1024 * 1024)
|
|
||||||
|
|
||||||
#define ALLOC_BIGCHUNK_LIMIT (64 * 1024)
|
#define ALLOC_BIGCHUNK_LIMIT (64 * 1024)
|
||||||
/* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
|
/* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
|
||||||
|
|
||||||
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
|
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
|
||||||
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
|
#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
|
||||||
|
|
||||||
|
/* Min safe value of allocation block size */
|
||||||
|
#define ALLOC_MIN_BLOCK_SIZE \
|
||||||
|
(ALLOC_SMALLCHUNK_LIMIT + ALLOC_CHUNKHDRSZ + ALLOC_BLOCKHDRSZ)
|
||||||
|
|
||||||
#define AllocPointerGetChunk(ptr) \
|
#define AllocPointerGetChunk(ptr) \
|
||||||
((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
|
((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
|
||||||
#define AllocChunkGetPointer(chk) \
|
#define AllocChunkGetPointer(chk) \
|
||||||
@ -95,6 +152,29 @@
|
|||||||
#define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
|
#define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset))
|
||||||
#define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size)
|
#define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These functions implement the MemoryContext API for AllocSet contexts.
|
||||||
|
*/
|
||||||
|
static void *AllocSetAlloc(MemoryContext context, Size size);
|
||||||
|
static void AllocSetFree(MemoryContext context, void *pointer);
|
||||||
|
static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
|
||||||
|
static void AllocSetInit(MemoryContext context);
|
||||||
|
static void AllocSetReset(MemoryContext context);
|
||||||
|
static void AllocSetDelete(MemoryContext context);
|
||||||
|
static void AllocSetStats(MemoryContext context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the virtual function table for AllocSet contexts.
|
||||||
|
*/
|
||||||
|
static MemoryContextMethods AllocSetMethods = {
|
||||||
|
AllocSetAlloc,
|
||||||
|
AllocSetFree,
|
||||||
|
AllocSetRealloc,
|
||||||
|
AllocSetInit,
|
||||||
|
AllocSetReset,
|
||||||
|
AllocSetDelete,
|
||||||
|
AllocSetStats
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
@ -127,52 +207,159 @@ AllocSetFreeIndex(Size size)
|
|||||||
* Public routines
|
* Public routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocSetInit
|
* AllocSetContextCreate
|
||||||
* Initializes given allocation set.
|
* Create a new AllocSet context.
|
||||||
*
|
*
|
||||||
* Note:
|
* parent: parent context, or NULL if top-level context
|
||||||
* The semantics of the mode are explained above. Limit is ignored
|
* name: name of context (for debugging --- string will be copied)
|
||||||
* for dynamic and static modes.
|
* minContextSize: minimum context size
|
||||||
*
|
* initBlockSize: initial allocation block size
|
||||||
* Exceptions:
|
* maxBlockSize: maximum allocation block size
|
||||||
* BadArg if set is invalid pointer.
|
|
||||||
* BadArg if mode is invalid.
|
|
||||||
*/
|
*/
|
||||||
void
|
MemoryContext
|
||||||
AllocSetInit(AllocSet set, AllocMode mode, Size limit)
|
AllocSetContextCreate(MemoryContext parent,
|
||||||
|
const char *name,
|
||||||
|
Size minContextSize,
|
||||||
|
Size initBlockSize,
|
||||||
|
Size maxBlockSize)
|
||||||
{
|
{
|
||||||
AssertArg(PointerIsValid(set));
|
AllocSet context;
|
||||||
AssertArg((int) DynamicAllocMode <= (int) mode);
|
|
||||||
AssertArg((int) mode <= (int) BoundedAllocMode);
|
/* Do the type-independent part of context creation */
|
||||||
|
context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
|
||||||
|
sizeof(AllocSetContext),
|
||||||
|
&AllocSetMethods,
|
||||||
|
parent,
|
||||||
|
name);
|
||||||
|
/*
|
||||||
|
* Make sure alloc parameters are safe, and save them
|
||||||
|
*/
|
||||||
|
initBlockSize = MAXALIGN(initBlockSize);
|
||||||
|
if (initBlockSize < ALLOC_MIN_BLOCK_SIZE)
|
||||||
|
initBlockSize = ALLOC_MIN_BLOCK_SIZE;
|
||||||
|
maxBlockSize = MAXALIGN(maxBlockSize);
|
||||||
|
if (maxBlockSize < initBlockSize)
|
||||||
|
maxBlockSize = initBlockSize;
|
||||||
|
context->initBlockSize = initBlockSize;
|
||||||
|
context->maxBlockSize = maxBlockSize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX mode is currently ignored and treated as DynamicAllocMode. XXX
|
* Grab always-allocated space, if requested
|
||||||
* limit is also ignored. This affects this whole file.
|
|
||||||
*/
|
*/
|
||||||
|
if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)
|
||||||
|
{
|
||||||
|
Size blksize = MAXALIGN(minContextSize);
|
||||||
|
AllocBlock block;
|
||||||
|
|
||||||
memset(set, 0, sizeof(AllocSetData));
|
block = (AllocBlock) malloc(blksize);
|
||||||
|
if (block == NULL)
|
||||||
|
elog(ERROR, "Memory exhausted in AllocSetContextCreate()");
|
||||||
|
block->aset = context;
|
||||||
|
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
|
||||||
|
block->endptr = ((char *) block) + blksize;
|
||||||
|
block->next = context->blocks;
|
||||||
|
context->blocks = block;
|
||||||
|
/* Mark block as not to be released at reset time */
|
||||||
|
context->keeper = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (MemoryContext) context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AllocSetInit
|
||||||
|
* Context-type-specific initialization routine.
|
||||||
|
*
|
||||||
|
* This is called by MemoryContextCreate() after setting up the
|
||||||
|
* generic MemoryContext fields and before linking the new context
|
||||||
|
* into the context tree. We must do whatever is needed to make the
|
||||||
|
* new context minimally valid for deletion. We must *not* risk
|
||||||
|
* failure --- thus, for example, allocating more memory is not cool.
|
||||||
|
* (AllocSetContextCreate can allocate memory when it gets control
|
||||||
|
* back, however.)
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
AllocSetInit(MemoryContext context)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Since MemoryContextCreate already zeroed the context node,
|
||||||
|
* we don't have to do anything here: it's already OK.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocSetReset
|
* AllocSetReset
|
||||||
* Frees all memory which is allocated in the given set.
|
* Frees all memory which is allocated in the given set.
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* Actually, this routine has some discretion about what to do.
|
||||||
* BadArg if set is invalid.
|
* It should mark all allocated chunks freed, but it need not
|
||||||
|
* necessarily give back all the resources the set owns. Our
|
||||||
|
* actual implementation is that we hang on to any "keeper"
|
||||||
|
* block specified for the set.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
AllocSetReset(AllocSet set)
|
AllocSetReset(MemoryContext context)
|
||||||
{
|
{
|
||||||
|
AllocSet set = (AllocSet) context;
|
||||||
AllocBlock block = set->blocks;
|
AllocBlock block = set->blocks;
|
||||||
AllocBlock next;
|
|
||||||
|
|
||||||
AssertArg(AllocSetIsValid(set));
|
AssertArg(AllocSetIsValid(set));
|
||||||
|
|
||||||
while (block != NULL)
|
while (block != NULL)
|
||||||
{
|
{
|
||||||
next = block->next;
|
AllocBlock next = block->next;
|
||||||
|
|
||||||
|
if (block == set->keeper)
|
||||||
|
{
|
||||||
|
/* Reset the block, but don't return it to malloc */
|
||||||
|
block->next = NULL;
|
||||||
|
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
|
||||||
|
#ifdef CLOBBER_FREED_MEMORY
|
||||||
|
/* 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
|
#ifdef CLOBBER_FREED_MEMORY
|
||||||
/* Wipe freed memory for debugging purposes */
|
/* Wipe freed memory for debugging purposes */
|
||||||
memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
|
memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
|
||||||
@ -181,38 +368,21 @@ AllocSetReset(AllocSet set)
|
|||||||
block = next;
|
block = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(set, 0, sizeof(AllocSetData));
|
/* Make it look empty, just in case... */
|
||||||
}
|
set->blocks = NULL;
|
||||||
|
MemSet(set->freelist, 0, sizeof(set->freelist));
|
||||||
/*
|
set->keeper = NULL;
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocSetAlloc
|
* AllocSetAlloc
|
||||||
* Returns pointer to allocated memory of given size; memory is added
|
* Returns pointer to allocated memory of given size; memory is added
|
||||||
* to the set.
|
* to the set.
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadArg if set is invalid.
|
|
||||||
* MemoryExhausted if allocation fails.
|
|
||||||
*/
|
*/
|
||||||
AllocPointer
|
static void *
|
||||||
AllocSetAlloc(AllocSet set, Size size)
|
AllocSetAlloc(MemoryContext context, Size size)
|
||||||
{
|
{
|
||||||
|
AllocSet set = (AllocSet) context;
|
||||||
AllocBlock block;
|
AllocBlock block;
|
||||||
AllocChunk chunk;
|
AllocChunk chunk;
|
||||||
AllocChunk priorfree = NULL;
|
AllocChunk priorfree = NULL;
|
||||||
@ -225,7 +395,6 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
/*
|
/*
|
||||||
* Lookup in the corresponding free list if there is a free chunk we
|
* Lookup in the corresponding free list if there is a free chunk we
|
||||||
* could reuse
|
* could reuse
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
fidx = AllocSetFreeIndex(size);
|
fidx = AllocSetFreeIndex(size);
|
||||||
for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
|
for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
|
||||||
@ -238,7 +407,6 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
/*
|
/*
|
||||||
* If one is found, remove it from the free list, make it again a
|
* If one is found, remove it from the free list, make it again a
|
||||||
* member of the alloc set and return its data address.
|
* member of the alloc set and return its data address.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
if (chunk != NULL)
|
if (chunk != NULL)
|
||||||
{
|
{
|
||||||
@ -284,7 +452,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
||||||
block = (AllocBlock) malloc(blksize);
|
block = (AllocBlock) malloc(blksize);
|
||||||
if (block == NULL)
|
if (block == NULL)
|
||||||
elog(FATAL, "Memory exhausted in AllocSetAlloc()");
|
elog(ERROR, "Memory exhausted in AllocSetAlloc()");
|
||||||
block->aset = set;
|
block->aset = set;
|
||||||
block->freeptr = block->endptr = ((char *) block) + blksize;
|
block->freeptr = block->endptr = ((char *) block) + blksize;
|
||||||
|
|
||||||
@ -317,7 +485,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
{
|
{
|
||||||
if (set->blocks == NULL)
|
if (set->blocks == NULL)
|
||||||
{
|
{
|
||||||
blksize = ALLOC_MIN_BLOCK_SIZE;
|
blksize = set->initBlockSize;
|
||||||
block = (AllocBlock) malloc(blksize);
|
block = (AllocBlock) malloc(blksize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -327,15 +495,18 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Special case: if very first allocation was for a large
|
* Special case: if very first allocation was for a large
|
||||||
* chunk, could have a funny-sized top block. Do something
|
* chunk (or we have a small "keeper" block), could have an
|
||||||
* reasonable.
|
* undersized top block. Do something reasonable.
|
||||||
*/
|
*/
|
||||||
if (blksize < ALLOC_MIN_BLOCK_SIZE)
|
if (blksize < set->initBlockSize)
|
||||||
blksize = ALLOC_MIN_BLOCK_SIZE;
|
blksize = set->initBlockSize;
|
||||||
/* Crank it up, but not past max */
|
else
|
||||||
blksize <<= 1;
|
{
|
||||||
if (blksize > ALLOC_MAX_BLOCK_SIZE)
|
/* Crank it up, but not past max */
|
||||||
blksize = ALLOC_MAX_BLOCK_SIZE;
|
blksize <<= 1;
|
||||||
|
if (blksize > set->maxBlockSize)
|
||||||
|
blksize = set->maxBlockSize;
|
||||||
|
}
|
||||||
/* Try to allocate it */
|
/* Try to allocate it */
|
||||||
block = (AllocBlock) malloc(blksize);
|
block = (AllocBlock) malloc(blksize);
|
||||||
|
|
||||||
@ -352,7 +523,7 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (block == NULL)
|
if (block == NULL)
|
||||||
elog(FATAL, "Memory exhausted in AllocSetAlloc()");
|
elog(ERROR, "Memory exhausted in AllocSetAlloc()");
|
||||||
block->aset = set;
|
block->aset = set;
|
||||||
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
|
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
|
||||||
block->endptr = ((char *) block) + blksize;
|
block->endptr = ((char *) block) + blksize;
|
||||||
@ -376,22 +547,12 @@ AllocSetAlloc(AllocSet set, Size size)
|
|||||||
/*
|
/*
|
||||||
* AllocSetFree
|
* AllocSetFree
|
||||||
* Frees allocated memory; memory is removed from the set.
|
* Frees allocated memory; memory is removed from the set.
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadArg if set is invalid.
|
|
||||||
* BadArg if pointer is invalid.
|
|
||||||
* BadArg if pointer is not member of set.
|
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
AllocSetFree(AllocSet set, AllocPointer pointer)
|
AllocSetFree(MemoryContext context, void *pointer)
|
||||||
{
|
{
|
||||||
AllocChunk chunk;
|
AllocSet set = (AllocSet) context;
|
||||||
|
AllocChunk chunk = AllocPointerGetChunk(pointer);
|
||||||
/* AssertArg(AllocSetIsValid(set)); */
|
|
||||||
/* AssertArg(AllocPointerIsValid(pointer)); */
|
|
||||||
AssertArg(AllocSetContains(set, pointer));
|
|
||||||
|
|
||||||
chunk = AllocPointerGetChunk(pointer);
|
|
||||||
|
|
||||||
#ifdef CLOBBER_FREED_MEMORY
|
#ifdef CLOBBER_FREED_MEMORY
|
||||||
/* Wipe freed memory for debugging purposes */
|
/* Wipe freed memory for debugging purposes */
|
||||||
@ -446,24 +607,15 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
|
|||||||
* Returns new pointer to allocated memory of given size; this memory
|
* Returns new pointer to allocated memory of given size; this memory
|
||||||
* is added to the set. Memory associated with given pointer is copied
|
* is added to the set. Memory associated with given pointer is copied
|
||||||
* into the new memory, and the old memory is freed.
|
* into the new memory, and the old memory is freed.
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadArg if set is invalid.
|
|
||||||
* BadArg if pointer is invalid.
|
|
||||||
* BadArg if pointer is not member of set.
|
|
||||||
* MemoryExhausted if allocation fails.
|
|
||||||
*/
|
*/
|
||||||
AllocPointer
|
static void *
|
||||||
AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
AllocSetRealloc(MemoryContext context, void *pointer, Size size)
|
||||||
{
|
{
|
||||||
|
AllocSet set = (AllocSet) context;
|
||||||
Size oldsize;
|
Size oldsize;
|
||||||
|
|
||||||
/* AssertArg(AllocSetIsValid(set)); */
|
|
||||||
/* AssertArg(AllocPointerIsValid(pointer)); */
|
|
||||||
AssertArg(AllocSetContains(set, pointer));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
|
* Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
|
||||||
* allocated area already is >= the new size. (In particular, we
|
* allocated area already is >= the new size. (In particular, we
|
||||||
* always fall out here if the requested size is a decrease.)
|
* always fall out here if the requested size is a decrease.)
|
||||||
*/
|
*/
|
||||||
@ -503,7 +655,7 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
|||||||
blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
|
||||||
block = (AllocBlock) realloc(block, blksize);
|
block = (AllocBlock) realloc(block, blksize);
|
||||||
if (block == NULL)
|
if (block == NULL)
|
||||||
elog(FATAL, "Memory exhausted in AllocSetReAlloc()");
|
elog(ERROR, "Memory exhausted in AllocSetReAlloc()");
|
||||||
block->freeptr = block->endptr = ((char *) block) + blksize;
|
block->freeptr = block->endptr = ((char *) block) + blksize;
|
||||||
|
|
||||||
/* Update pointers since block has likely been moved */
|
/* Update pointers since block has likely been moved */
|
||||||
@ -520,35 +672,26 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
|
|||||||
/* Normal small-chunk case: just do it by brute force. */
|
/* Normal small-chunk case: just do it by brute force. */
|
||||||
|
|
||||||
/* allocate new chunk */
|
/* allocate new chunk */
|
||||||
AllocPointer newPointer = AllocSetAlloc(set, size);
|
AllocPointer newPointer = AllocSetAlloc((MemoryContext) set, size);
|
||||||
|
|
||||||
/* transfer existing data (certain to fit) */
|
/* transfer existing data (certain to fit) */
|
||||||
memcpy(newPointer, pointer, oldsize);
|
memcpy(newPointer, pointer, oldsize);
|
||||||
|
|
||||||
/* free old chunk */
|
/* free old chunk */
|
||||||
AllocSetFree(set, pointer);
|
AllocSetFree((MemoryContext) set, pointer);
|
||||||
|
|
||||||
return newPointer;
|
return newPointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* AllocSetDump
|
|
||||||
* Displays allocated set.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AllocSetDump(AllocSet set)
|
|
||||||
{
|
|
||||||
elog(DEBUG, "Currently unable to dump AllocSet");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocSetStats
|
* AllocSetStats
|
||||||
* Displays stats about memory consumption of an allocset.
|
* Displays stats about memory consumption of an allocset.
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
AllocSetStats(AllocSet set, const char *ident)
|
AllocSetStats(MemoryContext context)
|
||||||
{
|
{
|
||||||
|
AllocSet set = (AllocSet) context;
|
||||||
long nblocks = 0;
|
long nblocks = 0;
|
||||||
long nchunks = 0;
|
long nchunks = 0;
|
||||||
long totalspace = 0;
|
long totalspace = 0;
|
||||||
@ -557,8 +700,6 @@ AllocSetStats(AllocSet set, const char *ident)
|
|||||||
AllocChunk chunk;
|
AllocChunk chunk;
|
||||||
int fidx;
|
int fidx;
|
||||||
|
|
||||||
AssertArg(AllocSetIsValid(set));
|
|
||||||
|
|
||||||
for (block = set->blocks; block != NULL; block = block->next)
|
for (block = set->blocks; block != NULL; block = block->next)
|
||||||
{
|
{
|
||||||
nblocks++;
|
nblocks++;
|
||||||
@ -576,6 +717,6 @@ AllocSetStats(AllocSet set, const char *ident)
|
|||||||
}
|
}
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n",
|
"%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n",
|
||||||
ident, totalspace, nblocks, freespace, nchunks,
|
set->header.name, totalspace, nblocks, freespace, nchunks,
|
||||||
totalspace - freespace);
|
totalspace - freespace);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* mcxt.c
|
* mcxt.c
|
||||||
* POSTGRES memory context code.
|
* POSTGRES memory context management code.
|
||||||
|
*
|
||||||
|
* This module handles context management operations that are independent
|
||||||
|
* of the particular kind of context being operated on. It calls
|
||||||
|
* context-type-specific operations via the function pointers in a
|
||||||
|
* context's MemoryContextMethods struct.
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.21 2000/05/21 02:23:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.22 2000/06/28 03:32:50 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -17,323 +23,440 @@
|
|||||||
|
|
||||||
#include "nodes/memnodes.h"
|
#include "nodes/memnodes.h"
|
||||||
#include "utils/excid.h"
|
#include "utils/excid.h"
|
||||||
#include "utils/module.h"
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#undef MemoryContextAlloc
|
|
||||||
#undef MemoryContextFree
|
|
||||||
#undef malloc
|
|
||||||
#undef free
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Global State
|
|
||||||
*/
|
|
||||||
static int MemoryContextEnableCount = 0;
|
|
||||||
|
|
||||||
#define MemoryContextEnabled (MemoryContextEnableCount > 0)
|
|
||||||
|
|
||||||
static OrderedSetData ActiveGlobalMemorySetData; /* uninitialized */
|
|
||||||
|
|
||||||
#define ActiveGlobalMemorySet (&ActiveGlobalMemorySetData)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* description of allocated memory representation goes here
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
|
|
||||||
#define PSIZEALL(PTR) (*((int32 *)(PTR) - 1) + sizeof (int32))
|
|
||||||
#define PSIZESKIP(PTR) ((char *)((int32 *)(PTR) + 1))
|
|
||||||
#define PSIZEFIND(PTR) ((char *)((int32 *)(PTR) - 1))
|
|
||||||
#define PSIZESPACE(LEN) ((LEN) + sizeof (int32))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* AllocSizeIsValid
|
|
||||||
* True iff 0 < size and size <= MaxAllocSize.
|
|
||||||
*/
|
|
||||||
#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* GLOBAL MEMORY *
|
* GLOBAL MEMORY *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CurrentMemoryContext
|
* CurrentMemoryContext
|
||||||
* Memory context for general global allocations.
|
* Default memory context for allocations.
|
||||||
*/
|
*/
|
||||||
DLLIMPORT MemoryContext CurrentMemoryContext = NULL;
|
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
|
* MemoryContextInit
|
||||||
*/
|
* Start up the memory-context subsystem.
|
||||||
|
|
||||||
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.
|
|
||||||
*
|
*
|
||||||
* Note:
|
* This must be called before creating contexts or allocating memory in
|
||||||
* Don't use this memory context for random allocations. If you
|
* contexts. TopMemoryContext and ErrorContext are initialized here;
|
||||||
* allocate something here, you are expected to clean it up when
|
* other contexts must be created afterwards.
|
||||||
* appropriate.
|
|
||||||
*/
|
|
||||||
MemoryContext TopMemoryContext = (MemoryContext) &TopGlobalMemoryData;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Module State
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* EnableMemoryContext
|
|
||||||
* Enables/disables memory management and global contexts.
|
|
||||||
*
|
*
|
||||||
* Note:
|
* In normal multi-backend operation, this is called once during
|
||||||
* This must be called before creating contexts or allocating memory.
|
* postmaster startup, and not at all by individual backend startup
|
||||||
* This must be called before other contexts are created.
|
* (since the backends inherit an already-initialized context subsystem
|
||||||
|
* by virtue of being forked off the postmaster).
|
||||||
*
|
*
|
||||||
* Exceptions:
|
* In a standalone backend this must be called during backend startup.
|
||||||
* BadArg if on is invalid.
|
|
||||||
* BadState if on is false when disabled.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
EnableMemoryContext(bool on)
|
MemoryContextInit(void)
|
||||||
{
|
{
|
||||||
static bool processing = false;
|
AssertState(TopMemoryContext == NULL);
|
||||||
|
/*
|
||||||
|
* 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 */
|
* MemoryContextDelete
|
||||||
/* initialize TopGlobalMemoryData.setData */
|
* Delete a context and its descendants, and release all space
|
||||||
AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
|
* allocated therein.
|
||||||
(Size) 0);
|
*
|
||||||
|
* 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 */
|
MemoryContextDeleteChildren(context);
|
||||||
OrderedSetInit(ActiveGlobalMemorySet,
|
/*
|
||||||
offsetof(struct GlobalMemoryData, elemData));
|
* We delink the context from its parent before deleting it,
|
||||||
OrderedElemPushInto(&TopGlobalMemoryData.elemData,
|
* so that if there's an error we won't have deleted/busted
|
||||||
ActiveGlobalMemorySet);
|
* contexts still attached to the context tree. Better a leak
|
||||||
|
* than a crash.
|
||||||
|
*/
|
||||||
|
if (context->parent)
|
||||||
|
{
|
||||||
|
MemoryContext parent = context->parent;
|
||||||
|
|
||||||
/* initialize CurrentMemoryContext */
|
if (context == parent->firstchild)
|
||||||
CurrentMemoryContext = TopMemoryContext;
|
{
|
||||||
|
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
|
else
|
||||||
{ /* cleanup */
|
{
|
||||||
GlobalMemory context;
|
/* Special case for startup: use good ol' malloc */
|
||||||
|
node = (MemoryContext) malloc(needed);
|
||||||
/* walk the list of allocations */
|
Assert(node != NULL);
|
||||||
while (PointerIsValid(context = (GlobalMemory)
|
|
||||||
OrderedSetGetHead(ActiveGlobalMemorySet)))
|
|
||||||
{
|
|
||||||
|
|
||||||
if (context == &TopGlobalMemoryData)
|
|
||||||
{
|
|
||||||
/* don't free it and clean it last */
|
|
||||||
OrderedElemPop(&TopGlobalMemoryData.elemData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
GlobalMemoryDestroy(context);
|
|
||||||
/* what is needed for the top? */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Freeing memory here should be safe as this is called only after
|
|
||||||
* all modules which allocate in TopMemoryContext have been
|
|
||||||
* disabled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* step through remaining allocations and log */
|
|
||||||
/* AllocSetStep(...); */
|
|
||||||
|
|
||||||
/* deallocate whatever is left */
|
|
||||||
AllocSetReset(&TopGlobalMemoryData.setData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
processing = false;
|
/* 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
|
* MemoryContextAlloc
|
||||||
* Returns pointer to aligned allocated memory in the given context.
|
* Allocate space within the specified context.
|
||||||
*
|
*
|
||||||
* Note:
|
* This could be turned into a macro, but we'd have to import
|
||||||
* none
|
* nodes/memnodes.h into postgres.h which seems a bad idea.
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called before InitMemoryManager.
|
|
||||||
* BadArg if context is invalid or if size is 0.
|
|
||||||
* BadAllocSize if size is larger than MaxAllocSize.
|
|
||||||
*/
|
*/
|
||||||
Pointer
|
void *
|
||||||
MemoryContextAlloc(MemoryContext context, Size size)
|
MemoryContextAlloc(MemoryContext context, Size size)
|
||||||
{
|
{
|
||||||
AssertState(MemoryContextEnabled);
|
|
||||||
AssertArg(MemoryContextIsValid(context));
|
AssertArg(MemoryContextIsValid(context));
|
||||||
|
|
||||||
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
|
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
|
||||||
("size=%d [0x%x]", size, size));
|
("size=%d [0x%x]", size, size));
|
||||||
|
|
||||||
return context->method->alloc(context, size);
|
return (*context->methods->alloc) (context, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MemoryContextFree
|
* pfree
|
||||||
* Frees allocated memory referenced by pointer in the given context.
|
* Release an allocated chunk.
|
||||||
*
|
|
||||||
* Note:
|
|
||||||
* none
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* ???
|
|
||||||
* BadArgumentsErr if firstTime is true for subsequent calls.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
MemoryContextFree(MemoryContext context, Pointer pointer)
|
pfree(void *pointer)
|
||||||
{
|
{
|
||||||
AssertState(MemoryContextEnabled);
|
StandardChunkHeader *header;
|
||||||
AssertArg(MemoryContextIsValid(context));
|
|
||||||
AssertArg(PointerIsValid(pointer));
|
|
||||||
|
|
||||||
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
|
* repalloc
|
||||||
* Returns pointer to aligned allocated memory in the given context.
|
|
||||||
*
|
*
|
||||||
* Note:
|
|
||||||
* none
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* ???
|
|
||||||
* BadArgumentsErr if firstTime is true for subsequent calls.
|
|
||||||
*/
|
*/
|
||||||
Pointer
|
void *
|
||||||
MemoryContextRealloc(MemoryContext context,
|
repalloc(void *pointer, Size size)
|
||||||
Pointer pointer,
|
|
||||||
Size size)
|
|
||||||
{
|
{
|
||||||
AssertState(MemoryContextEnabled);
|
StandardChunkHeader *header;
|
||||||
AssertArg(MemoryContextIsValid(context));
|
|
||||||
AssertArg(PointerIsValid(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));
|
||||||
|
|
||||||
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
|
LogTrap(!AllocSizeIsValid(size), BadAllocSize,
|
||||||
("size=%d [0x%x]", size, size));
|
("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
|
* MemoryContextSwitchTo
|
||||||
* Returns the current context; installs the given context.
|
* Returns the current context; installs the given context.
|
||||||
*
|
|
||||||
* Note:
|
|
||||||
* none
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
* BadArg if context is invalid.
|
|
||||||
*/
|
*/
|
||||||
MemoryContext
|
MemoryContext
|
||||||
MemoryContextSwitchTo(MemoryContext context)
|
MemoryContextSwitchTo(MemoryContext context)
|
||||||
{
|
{
|
||||||
MemoryContext old;
|
MemoryContext old;
|
||||||
|
|
||||||
AssertState(MemoryContextEnabled);
|
|
||||||
AssertArg(MemoryContextIsValid(context));
|
AssertArg(MemoryContextIsValid(context));
|
||||||
|
|
||||||
old = CurrentMemoryContext;
|
old = CurrentMemoryContext;
|
||||||
@ -342,195 +465,18 @@ MemoryContextSwitchTo(MemoryContext context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* External Functions
|
* MemoryContextStrdup
|
||||||
|
* Like strdup(), but allocate from the specified context
|
||||||
*/
|
*/
|
||||||
/*
|
char *
|
||||||
* CreateGlobalMemory
|
MemoryContextStrdup(MemoryContext context, const char *string)
|
||||||
* 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 */
|
|
||||||
{
|
{
|
||||||
GlobalMemory context;
|
char *nstr;
|
||||||
MemoryContext savecxt;
|
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);
|
return nstr;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
* 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 {
|
* struct PortalD {
|
||||||
* char* name;
|
* char* name;
|
||||||
* classObj(PortalVariableMemory) variable;
|
* classObj(MemoryContext) heap;
|
||||||
* classObj(PortalHeapMemory) heap;
|
|
||||||
* List queryDesc;
|
* List queryDesc;
|
||||||
* EState state;
|
* EState state;
|
||||||
* void (*cleanup) ARGS((Portal portal));
|
* void (*cleanup) ARGS((Portal portal));
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* I hope this makes things clearer to whoever reads this -cim 2/22/91
|
* I hope this makes things clearer to whoever reads this -cim 2/22/91
|
||||||
*
|
|
||||||
* Here is an old comment taken from nodes/memnodes.h
|
|
||||||
*
|
|
||||||
* MemoryContext
|
|
||||||
* A logical context in which memory allocations occur.
|
|
||||||
*
|
|
||||||
* The types of memory contexts can be thought of as members of the
|
|
||||||
* following inheritance hierarchy with properties summarized below.
|
|
||||||
*
|
|
||||||
* Node
|
|
||||||
* |
|
|
||||||
* MemoryContext___
|
|
||||||
* / \
|
|
||||||
* GlobalMemory PortalMemoryContext
|
|
||||||
* / \
|
|
||||||
* PortalVariableMemory PortalHeapMemory
|
|
||||||
*
|
|
||||||
* Flushed at Flushed at Checkpoints
|
|
||||||
* Transaction Portal
|
|
||||||
* Commit Close
|
|
||||||
*
|
|
||||||
* GlobalMemory n n n
|
|
||||||
* PortalVariableMemory n y n
|
|
||||||
* PortalHeapMemory y y y *
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "lib/hasht.h"
|
#include "lib/hasht.h"
|
||||||
#include "utils/module.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/portal.h"
|
#include "utils/portal.h"
|
||||||
|
|
||||||
static void CollectNamedPortals(Portal *portalP, int destroy);
|
static void CollectNamedPortals(Portal *portalP, int destroy);
|
||||||
static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
|
|
||||||
static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
|
|
||||||
static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* ALLOCFREE_ERROR_ABORT
|
|
||||||
* define this if you want a core dump when you try to
|
|
||||||
* free memory already freed -cim 2/9/91
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
#undef ALLOCFREE_ERROR_ABORT
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Global state
|
* Global state
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int PortalManagerEnableCount = 0;
|
|
||||||
|
|
||||||
#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
|
#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
|
||||||
|
|
||||||
typedef struct portalhashent
|
typedef struct portalhashent
|
||||||
@ -109,8 +70,6 @@ typedef struct portalhashent
|
|||||||
Portal portal;
|
Portal portal;
|
||||||
} PortalHashEnt;
|
} PortalHashEnt;
|
||||||
|
|
||||||
#define PortalManagerEnabled (PortalManagerEnableCount >= 1)
|
|
||||||
|
|
||||||
static HTAB *PortalHashTable = NULL;
|
static HTAB *PortalHashTable = NULL;
|
||||||
|
|
||||||
#define PortalHashTableLookup(NAME, PORTAL) \
|
#define PortalHashTableLookup(NAME, PORTAL) \
|
||||||
@ -158,263 +117,13 @@ do { \
|
|||||||
elog(NOTICE, "trying to delete portal name that does not exist."); \
|
elog(NOTICE, "trying to delete portal name that does not exist."); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
static GlobalMemory PortalMemory = NULL;
|
static MemoryContext PortalMemory = NULL;
|
||||||
static char PortalMemoryName[] = "Portal";
|
|
||||||
|
|
||||||
static Portal BlankPortal = NULL;
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* Internal class definitions
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
typedef struct HeapMemoryBlockData
|
|
||||||
{
|
|
||||||
AllocSetData setData;
|
|
||||||
FixedItemData itemData;
|
|
||||||
} HeapMemoryBlockData;
|
|
||||||
|
|
||||||
typedef HeapMemoryBlockData *HeapMemoryBlock;
|
|
||||||
|
|
||||||
#define HEAPMEMBLOCK(context) \
|
|
||||||
((HeapMemoryBlock)(context)->block)
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
|
||||||
* Variable and heap memory methods
|
|
||||||
* ----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
/* ----------------
|
|
||||||
* PortalVariableMemoryAlloc
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static Pointer
|
|
||||||
PortalVariableMemoryAlloc(PortalVariableMemory this,
|
|
||||||
Size size)
|
|
||||||
{
|
|
||||||
return AllocSetAlloc(&this->setData, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalVariableMemoryFree
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
PortalVariableMemoryFree(PortalVariableMemory this,
|
|
||||||
Pointer pointer)
|
|
||||||
{
|
|
||||||
AllocSetFree(&this->setData, pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalVariableMemoryRealloc
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static Pointer
|
|
||||||
PortalVariableMemoryRealloc(PortalVariableMemory this,
|
|
||||||
Pointer pointer,
|
|
||||||
Size size)
|
|
||||||
{
|
|
||||||
return AllocSetRealloc(&this->setData, pointer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalVariableMemoryGetName
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static char *
|
|
||||||
PortalVariableMemoryGetName(PortalVariableMemory this)
|
|
||||||
{
|
|
||||||
return vararg_format("%s-var", PortalVariableMemoryGetPortal(this)->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalVariableMemoryDump
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
PortalVariableMemoryDump(PortalVariableMemory this)
|
|
||||||
{
|
|
||||||
printf("--\n%s:\n", PortalVariableMemoryGetName(this));
|
|
||||||
|
|
||||||
AllocSetDump(&this->setData); /* XXX is this the right interface */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalHeapMemoryAlloc
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static Pointer
|
|
||||||
PortalHeapMemoryAlloc(PortalHeapMemory this,
|
|
||||||
Size size)
|
|
||||||
{
|
|
||||||
HeapMemoryBlock block = HEAPMEMBLOCK(this);
|
|
||||||
|
|
||||||
AssertState(PointerIsValid(block));
|
|
||||||
|
|
||||||
return AllocSetAlloc(&block->setData, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalHeapMemoryFree
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
PortalHeapMemoryFree(PortalHeapMemory this,
|
|
||||||
Pointer pointer)
|
|
||||||
{
|
|
||||||
HeapMemoryBlock block = HEAPMEMBLOCK(this);
|
|
||||||
|
|
||||||
AssertState(PointerIsValid(block));
|
|
||||||
|
|
||||||
if (AllocSetContains(&block->setData, pointer))
|
|
||||||
AllocSetFree(&block->setData, pointer);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
elog(NOTICE,
|
|
||||||
"PortalHeapMemoryFree: 0x%p not in alloc set!",
|
|
||||||
pointer);
|
|
||||||
#ifdef ALLOCFREE_ERROR_ABORT
|
|
||||||
Assert(AllocSetContains(&block->setData, pointer));
|
|
||||||
#endif /* ALLOCFREE_ERROR_ABORT */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalHeapMemoryRealloc
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static Pointer
|
|
||||||
PortalHeapMemoryRealloc(PortalHeapMemory this,
|
|
||||||
Pointer pointer,
|
|
||||||
Size size)
|
|
||||||
{
|
|
||||||
HeapMemoryBlock block = HEAPMEMBLOCK(this);
|
|
||||||
|
|
||||||
AssertState(PointerIsValid(block));
|
|
||||||
|
|
||||||
return AllocSetRealloc(&block->setData, pointer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalHeapMemoryGetName
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static char *
|
|
||||||
PortalHeapMemoryGetName(PortalHeapMemory this)
|
|
||||||
{
|
|
||||||
return vararg_format("%s-heap", PortalHeapMemoryGetPortal(this)->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalHeapMemoryDump
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
PortalHeapMemoryDump(PortalHeapMemory this)
|
|
||||||
{
|
|
||||||
HeapMemoryBlock block;
|
|
||||||
|
|
||||||
printf("--\n%s:\n", PortalHeapMemoryGetName(this));
|
|
||||||
|
|
||||||
/* XXX is this the right interface */
|
|
||||||
if (PointerIsValid(this->block))
|
|
||||||
AllocSetDump(&HEAPMEMBLOCK(this)->setData);
|
|
||||||
|
|
||||||
/* dump the stack too */
|
|
||||||
for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
|
|
||||||
PointerIsValid(block);
|
|
||||||
block = (HeapMemoryBlock)
|
|
||||||
FixedStackGetNext(&this->stackData, (Pointer) block))
|
|
||||||
{
|
|
||||||
|
|
||||||
printf("--\n");
|
|
||||||
AllocSetDump(&block->setData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
|
||||||
* variable / heap context method tables
|
|
||||||
* ----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
|
|
||||||
PortalVariableMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
|
|
||||||
PortalVariableMemoryFree, /* void (*)(this, Pointer) pfree */
|
|
||||||
PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer) repalloc */
|
|
||||||
PortalVariableMemoryGetName,/* char* (*)(this) getName */
|
|
||||||
PortalVariableMemoryDump /* void (*)(this) dump */
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
|
|
||||||
PortalHeapMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
|
|
||||||
PortalHeapMemoryFree, /* void (*)(this, Pointer) pfree */
|
|
||||||
PortalHeapMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
|
|
||||||
PortalHeapMemoryGetName, /* char* (*)(this) getName */
|
|
||||||
PortalHeapMemoryDump /* void (*)(this) dump */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* private internal support routines
|
* private internal support routines
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
/* ----------------
|
|
||||||
* CreateNewBlankPortal
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
CreateNewBlankPortal()
|
|
||||||
{
|
|
||||||
Portal portal;
|
|
||||||
|
|
||||||
AssertState(!PortalIsValid(BlankPortal));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* make new portal structure
|
|
||||||
*/
|
|
||||||
portal = (Portal)
|
|
||||||
MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize portal variable context
|
|
||||||
*/
|
|
||||||
NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
|
|
||||||
AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
|
|
||||||
portal->variable.method = &PortalVariableContextMethodsData;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize portal heap context
|
|
||||||
*/
|
|
||||||
NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
|
|
||||||
portal->heap.block = NULL;
|
|
||||||
FixedStackInit(&portal->heap.stackData,
|
|
||||||
offsetof(HeapMemoryBlockData, itemData));
|
|
||||||
portal->heap.method = &PortalHeapContextMethodsData;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* set bogus portal name
|
|
||||||
*/
|
|
||||||
portal->name = "** Blank Portal **";
|
|
||||||
|
|
||||||
/* initialize portal query */
|
|
||||||
portal->queryDesc = NULL;
|
|
||||||
portal->attinfo = NULL;
|
|
||||||
portal->state = NULL;
|
|
||||||
portal->cleanup = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* install blank portal
|
|
||||||
*/
|
|
||||||
BlankPortal = portal;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
PortalNameIsSpecial(char *pname)
|
|
||||||
{
|
|
||||||
if (strcmp(pname, VACPNAME) == 0)
|
|
||||||
return true;
|
|
||||||
if (strcmp(pname, TRUNCPNAME) == 0)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine is used to collect all portals created in this xaction
|
* This routine is used to collect all portals created in this xaction
|
||||||
@ -447,12 +156,6 @@ CollectNamedPortals(Portal *portalP, int destroy)
|
|||||||
Assert(portalP);
|
Assert(portalP);
|
||||||
Assert(*portalP);
|
Assert(*portalP);
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't delete special portals, up to portal creator to do this
|
|
||||||
*/
|
|
||||||
if (PortalNameIsSpecial((*portalP)->name))
|
|
||||||
return;
|
|
||||||
|
|
||||||
portalList[listIndex] = *portalP;
|
portalList[listIndex] = *portalP;
|
||||||
listIndex++;
|
listIndex++;
|
||||||
if (listIndex == maxIndex)
|
if (listIndex == maxIndex)
|
||||||
@ -472,179 +175,50 @@ AtEOXact_portals()
|
|||||||
CollectNamedPortals(NULL, 1);
|
CollectNamedPortals(NULL, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* PortalDump
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
#ifdef NOT_USED
|
|
||||||
static void
|
|
||||||
PortalDump(Portal *thisP, int dummy)
|
|
||||||
{
|
|
||||||
/* XXX state/argument checking here */
|
|
||||||
|
|
||||||
PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
|
|
||||||
PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* DumpPortals
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
#ifdef NOT_USED
|
|
||||||
static void
|
|
||||||
DumpPortals()
|
|
||||||
{
|
|
||||||
/* XXX state checking here */
|
|
||||||
|
|
||||||
HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* public portal interface functions
|
* public portal interface functions
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* EnablePortalManager
|
* EnablePortalManager
|
||||||
* Enables/disables the portal management module.
|
* Enables the portal management module at backend startup.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
EnablePortalManager(bool on)
|
EnablePortalManager(void)
|
||||||
{
|
{
|
||||||
static bool processing = false;
|
|
||||||
HASHCTL ctl;
|
HASHCTL ctl;
|
||||||
|
|
||||||
AssertState(!processing);
|
Assert(PortalMemory == NULL);
|
||||||
AssertArg(BoolIsValid(on));
|
|
||||||
|
|
||||||
if (BypassEnable(&PortalManagerEnableCount, on))
|
PortalMemory = AllocSetContextCreate(TopMemoryContext,
|
||||||
return;
|
"PortalMemory",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
processing = true;
|
ctl.keysize = MAX_PORTALNAME_LEN;
|
||||||
|
ctl.datasize = sizeof(Portal);
|
||||||
|
|
||||||
if (on)
|
/*
|
||||||
{ /* initialize */
|
* use PORTALS_PER_USER, defined in utils/portal.h as a guess of
|
||||||
EnableMemoryContext(true);
|
* how many hash table entries to create, initially
|
||||||
|
*/
|
||||||
PortalMemory = CreateGlobalMemory(PortalMemoryName);
|
PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetPortalByName
|
* GetPortalByName
|
||||||
* Returns a portal given a portal name; returns blank portal given
|
* Returns a portal given a portal name, or NULL if name not found.
|
||||||
* NULL; returns invalid portal if portal not found.
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
*/
|
*/
|
||||||
Portal
|
Portal
|
||||||
GetPortalByName(char *name)
|
GetPortalByName(char *name)
|
||||||
{
|
{
|
||||||
Portal portal;
|
Portal portal;
|
||||||
|
|
||||||
AssertState(PortalManagerEnabled);
|
|
||||||
|
|
||||||
if (PointerIsValid(name))
|
if (PointerIsValid(name))
|
||||||
PortalHashTableLookup(name, portal);
|
PortalHashTableLookup(name, portal);
|
||||||
else
|
else
|
||||||
{
|
portal = NULL;
|
||||||
if (!PortalIsValid(BlankPortal))
|
|
||||||
CreateNewBlankPortal();
|
|
||||||
portal = BlankPortal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return portal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* BlankPortalAssignName
|
|
||||||
* Returns former blank portal as portal with given name.
|
|
||||||
*
|
|
||||||
* Side effect:
|
|
||||||
* All references to the former blank portal become incorrect.
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
* BadState if called without an intervening call to GetPortalByName(NULL).
|
|
||||||
* BadArg if portal name is invalid.
|
|
||||||
* "WARN" if portal name is in use.
|
|
||||||
*/
|
|
||||||
Portal
|
|
||||||
BlankPortalAssignName(char *name) /* XXX PortalName */
|
|
||||||
{
|
|
||||||
Portal portal;
|
|
||||||
uint16 length;
|
|
||||||
|
|
||||||
AssertState(PortalManagerEnabled);
|
|
||||||
AssertState(PortalIsValid(BlankPortal));
|
|
||||||
AssertArg(PointerIsValid(name)); /* XXX PortalName */
|
|
||||||
|
|
||||||
portal = GetPortalByName(name);
|
|
||||||
if (PortalIsValid(portal))
|
|
||||||
{
|
|
||||||
elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
|
|
||||||
return portal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* remove blank portal
|
|
||||||
*/
|
|
||||||
portal = BlankPortal;
|
|
||||||
BlankPortal = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* initialize portal name
|
|
||||||
*/
|
|
||||||
length = 1 + strlen(name);
|
|
||||||
portal->name = (char *)
|
|
||||||
MemoryContextAlloc((MemoryContext) &portal->variable, length);
|
|
||||||
|
|
||||||
strncpy(portal->name, name, length);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* put portal in table
|
|
||||||
*/
|
|
||||||
PortalHashTableInsert(portal);
|
|
||||||
|
|
||||||
return portal;
|
return portal;
|
||||||
}
|
}
|
||||||
@ -666,7 +240,6 @@ PortalSetQuery(Portal portal,
|
|||||||
EState *state,
|
EState *state,
|
||||||
void (*cleanup) (Portal portal))
|
void (*cleanup) (Portal portal))
|
||||||
{
|
{
|
||||||
AssertState(PortalManagerEnabled);
|
|
||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
AssertArg(IsA((Node *) state, EState));
|
AssertArg(IsA((Node *) state, EState));
|
||||||
|
|
||||||
@ -687,7 +260,6 @@ PortalSetQuery(Portal portal,
|
|||||||
QueryDesc *
|
QueryDesc *
|
||||||
PortalGetQueryDesc(Portal portal)
|
PortalGetQueryDesc(Portal portal)
|
||||||
{
|
{
|
||||||
AssertState(PortalManagerEnabled);
|
|
||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
|
|
||||||
return portal->queryDesc;
|
return portal->queryDesc;
|
||||||
@ -704,7 +276,6 @@ PortalGetQueryDesc(Portal portal)
|
|||||||
EState *
|
EState *
|
||||||
PortalGetState(Portal portal)
|
PortalGetState(Portal portal)
|
||||||
{
|
{
|
||||||
AssertState(PortalManagerEnabled);
|
|
||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
|
|
||||||
return portal->state;
|
return portal->state;
|
||||||
@ -714,63 +285,48 @@ PortalGetState(Portal portal)
|
|||||||
* CreatePortal
|
* CreatePortal
|
||||||
* Returns a new portal given a name.
|
* Returns a new portal given a name.
|
||||||
*
|
*
|
||||||
* Note:
|
|
||||||
* This is expected to be of very limited usability. See instead,
|
|
||||||
* BlankPortalAssignName.
|
|
||||||
*
|
|
||||||
* Exceptions:
|
* Exceptions:
|
||||||
* BadState if called when disabled.
|
* BadState if called when disabled.
|
||||||
* BadArg if portal name is invalid.
|
* BadArg if portal name is invalid.
|
||||||
* "WARN" if portal name is in use.
|
* "NOTICE" if portal name is in use (existing portal is returned!)
|
||||||
*/
|
*/
|
||||||
Portal
|
Portal
|
||||||
CreatePortal(char *name) /* XXX PortalName */
|
CreatePortal(char *name)
|
||||||
{
|
{
|
||||||
Portal portal;
|
Portal portal;
|
||||||
uint16 length;
|
|
||||||
|
|
||||||
AssertState(PortalManagerEnabled);
|
AssertArg(PointerIsValid(name));
|
||||||
AssertArg(PointerIsValid(name)); /* XXX PortalName */
|
|
||||||
|
|
||||||
portal = GetPortalByName(name);
|
portal = GetPortalByName(name);
|
||||||
if (PortalIsValid(portal))
|
if (PortalIsValid(portal))
|
||||||
{
|
{
|
||||||
elog(NOTICE, "CreatePortal: portal %s already exists", name);
|
elog(NOTICE, "CreatePortal: portal \"%s\" already exists", name);
|
||||||
return portal;
|
return portal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make new portal structure */
|
/* make new portal structure */
|
||||||
portal = (Portal)
|
portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
|
||||||
MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
|
|
||||||
|
|
||||||
/* initialize portal variable context */
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* initialize portal name */
|
/* initialize portal name */
|
||||||
length = 1 + strlen(name);
|
portal->name = MemoryContextStrdup(PortalMemory, name);
|
||||||
portal->name = (char *)
|
|
||||||
MemoryContextAlloc((MemoryContext) &portal->variable, length);
|
/* initialize portal heap context */
|
||||||
strncpy(portal->name, name, length);
|
portal->heap = AllocSetContextCreate(PortalMemory,
|
||||||
|
"PortalHeapMemory",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/* initialize portal query */
|
/* initialize portal query */
|
||||||
portal->queryDesc = NULL;
|
portal->queryDesc = NULL;
|
||||||
portal->attinfo = NULL;
|
portal->attinfo = NULL;
|
||||||
portal->state = NULL;
|
portal->state = NULL;
|
||||||
|
|
||||||
portal->cleanup = NULL;
|
portal->cleanup = NULL;
|
||||||
|
|
||||||
/* put portal in table */
|
/* put portal in table */
|
||||||
PortalHashTableInsert(portal);
|
PortalHashTableInsert(portal);
|
||||||
|
|
||||||
/* Trap(PointerIsValid(name), Unimplemented); */
|
|
||||||
return portal;
|
return portal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,240 +343,29 @@ PortalDrop(Portal *portalP)
|
|||||||
{
|
{
|
||||||
Portal portal = *portalP;
|
Portal portal = *portalP;
|
||||||
|
|
||||||
AssertState(PortalManagerEnabled);
|
|
||||||
AssertArg(PortalIsValid(portal));
|
AssertArg(PortalIsValid(portal));
|
||||||
|
|
||||||
/* remove portal from table if not blank portal */
|
/* remove portal from hash table */
|
||||||
if (portal != BlankPortal)
|
PortalHashTableDelete(portal);
|
||||||
PortalHashTableDelete(portal);
|
|
||||||
|
|
||||||
/* reset portal */
|
/* reset portal */
|
||||||
if (PointerIsValid(portal->cleanup))
|
if (PointerIsValid(portal->cleanup))
|
||||||
(*portal->cleanup) (portal);
|
(*portal->cleanup) (portal);
|
||||||
|
|
||||||
PortalResetHeapMemory(portal);
|
/* release subsidiary storage */
|
||||||
MemoryContextFree((MemoryContext) &portal->variable,
|
MemoryContextDelete(PortalGetHeapMemory(portal));
|
||||||
(Pointer) portal->name);
|
|
||||||
AllocSetReset(&portal->variable.setData); /* XXX log */
|
|
||||||
|
|
||||||
/*
|
/* release name and portal data (both are in PortalMemory) */
|
||||||
* In the case of a transaction abort it is possible that we get
|
pfree(portal->name);
|
||||||
* called while one of the memory contexts of the portal we're
|
pfree(portal);
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PortalGetHeapMemory
|
* PortalGetHeapMemory
|
||||||
* Returns heap memory context for a given portal.
|
* Returns heap memory context for a given portal.
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
* BadArg if portal is invalid.
|
|
||||||
*/
|
*/
|
||||||
PortalHeapMemory
|
MemoryContext
|
||||||
PortalGetHeapMemory(Portal portal)
|
PortalGetHeapMemory(Portal portal)
|
||||||
{
|
{
|
||||||
return &portal->heap;
|
return portal->heap;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PortalVariableMemoryGetPortal
|
|
||||||
* Returns portal containing given variable memory context.
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
* BadArg if context is invalid.
|
|
||||||
*/
|
|
||||||
static Portal
|
|
||||||
PortalVariableMemoryGetPortal(PortalVariableMemory context)
|
|
||||||
{
|
|
||||||
return (Portal) ((char *) context - offsetof(PortalD, variable));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PortalHeapMemoryGetPortal
|
|
||||||
* Returns portal containing given heap memory context.
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
* BadArg if context is invalid.
|
|
||||||
*/
|
|
||||||
static Portal
|
|
||||||
PortalHeapMemoryGetPortal(PortalHeapMemory context)
|
|
||||||
{
|
|
||||||
return (Portal) ((char *) context - offsetof(PortalD, heap));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PortalVariableMemoryGetHeapMemory
|
|
||||||
* Returns heap memory context associated with given variable memory.
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
* BadArg if context is invalid.
|
|
||||||
*/
|
|
||||||
#ifdef NOT_USED
|
|
||||||
PortalHeapMemory
|
|
||||||
PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
|
|
||||||
{
|
|
||||||
return ((PortalHeapMemory) ((char *) context
|
|
||||||
- offsetof(PortalD, variable)
|
|
||||||
+offsetof(PortalD, heap)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PortalHeapMemoryGetVariableMemory
|
|
||||||
* Returns variable memory context associated with given heap memory.
|
|
||||||
*
|
|
||||||
* Exceptions:
|
|
||||||
* BadState if called when disabled.
|
|
||||||
* BadArg if context is invalid.
|
|
||||||
*/
|
|
||||||
static PortalVariableMemory
|
|
||||||
PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
|
|
||||||
{
|
|
||||||
return ((PortalVariableMemory) ((char *) context
|
|
||||||
- offsetof(PortalD, heap)
|
|
||||||
+offsetof(PortalD, variable)));
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: command.h,v 1.18 2000/04/12 17:16:31 momjian Exp $
|
* $Id: command.h,v 1.19 2000/06/28 03:32:57 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include "utils/portal.h"
|
#include "utils/portal.h"
|
||||||
|
|
||||||
extern MemoryContext PortalExecutorHeapMemory;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PerformPortalFetch
|
* PerformPortalFetch
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: hashjoin.h,v 1.16 2000/01/26 05:58:05 momjian Exp $
|
* $Id: hashjoin.h,v 1.17 2000/06/28 03:33:05 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -22,20 +22,19 @@
|
|||||||
*
|
*
|
||||||
* Each active hashjoin has a HashJoinTable control block which is
|
* Each active hashjoin has a HashJoinTable control block which is
|
||||||
* palloc'd in the executor's context. All other storage needed for
|
* palloc'd in the executor's context. All other storage needed for
|
||||||
* the hashjoin is kept in a private "named portal", one for each hashjoin.
|
* the hashjoin is kept in private memory contexts, two for each hashjoin.
|
||||||
* This makes it easy and fast to release the storage when we don't need it
|
* This makes it easy and fast to release the storage when we don't need it
|
||||||
* anymore.
|
* anymore.
|
||||||
*
|
*
|
||||||
* The portal manager guarantees that portals will be discarded at end of
|
* The contexts are made children of TransactionCommandContext, ensuring
|
||||||
* transaction, so we have no problem with a memory leak if the join is
|
* that they will be discarded at end of statement even if the join is
|
||||||
* aborted early by an error. (Likewise, any temporary files we make will
|
* aborted early by an error. (Likewise, any temporary files we make will
|
||||||
* be cleaned up by the virtual file manager in event of an error.)
|
* be cleaned up by the virtual file manager in event of an error.)
|
||||||
*
|
*
|
||||||
* Storage that should live through the entire join is allocated from the
|
* Storage that should live through the entire join is allocated from the
|
||||||
* portal's "variable context", while storage that is only wanted for the
|
* "hashCxt", while storage that is only wanted for the current batch is
|
||||||
* current batch is allocated in the portal's "heap context". By popping
|
* allocated in the "batchCxt". By resetting the batchCxt at the end of
|
||||||
* the portal's heap at the end of a batch, we free all the per-batch storage
|
* each batch, we free all the per-batch storage reliably and without tedium.
|
||||||
* reliably and without tedium.
|
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -80,15 +79,6 @@ typedef struct HashTableData
|
|||||||
* to hash buckets and output.
|
* to hash buckets and output.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Ugly kluge: myPortal ought to be declared as type Portal (ie,
|
|
||||||
* PortalD*) but if we try to include utils/portal.h here, we end up
|
|
||||||
* with a circular dependency of include files! Until the various
|
|
||||||
* node.h files are restructured in a cleaner way, we have to fake it.
|
|
||||||
* The most reliable fake seems to be to declare myPortal as void *
|
|
||||||
* and then cast it to the right things in nodeHash.c.
|
|
||||||
*/
|
|
||||||
void *myPortal; /* where to keep working storage */
|
|
||||||
MemoryContext hashCxt; /* context for whole-hash-join storage */
|
MemoryContext hashCxt; /* context for whole-hash-join storage */
|
||||||
MemoryContext batchCxt; /* context for this-batch-only storage */
|
MemoryContext batchCxt; /* context for this-batch-only storage */
|
||||||
} HashTableData;
|
} HashTableData;
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "utils/fcache.h"
|
#include "utils/fcache.h"
|
||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
#include "utils/portal.h"
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "catalog/pg_language.h"
|
#include "catalog/pg_language.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
@ -95,4 +94,6 @@ extern void *SPI_repalloc(void *pointer, Size size);
|
|||||||
extern void SPI_pfree(void *pointer);
|
extern void SPI_pfree(void *pointer);
|
||||||
extern void SPI_freetuple(HeapTuple pointer);
|
extern void SPI_freetuple(HeapTuple pointer);
|
||||||
|
|
||||||
|
extern void AtEOXact_SPI(void);
|
||||||
|
|
||||||
#endif /* SPI_H */
|
#endif /* SPI_H */
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* spi.c
|
* spi.c
|
||||||
* Server Programming Interface private declarations
|
* Server Programming Interface private declarations
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.6 1999/07/15 15:21:14 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.7 2000/06/28 03:33:05 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -17,7 +17,8 @@ typedef struct
|
|||||||
List *qtlist;
|
List *qtlist;
|
||||||
uint32 processed; /* by Executor */
|
uint32 processed; /* by Executor */
|
||||||
SPITupleTable *tuptable;
|
SPITupleTable *tuptable;
|
||||||
Portal portal; /* portal per procedure */
|
MemoryContext procCxt; /* procedure context */
|
||||||
|
MemoryContext execCxt; /* executor context */
|
||||||
MemoryContext savedcxt;
|
MemoryContext savedcxt;
|
||||||
CommandId savedId;
|
CommandId savedId;
|
||||||
} _SPI_connection;
|
} _SPI_connection;
|
||||||
|
@ -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) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: pqsignal.h,v 1.13 2000/06/15 00:52:11 momjian Exp $
|
* $Id: pqsignal.h,v 1.14 2000/06/28 03:33:14 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This shouldn't be in libpq, but the monitor and some other
|
* This shouldn't be in libpq, but the monitor and some other
|
||||||
@ -24,28 +24,18 @@
|
|||||||
extern sigset_t UnBlockSig,
|
extern sigset_t UnBlockSig,
|
||||||
BlockSig;
|
BlockSig;
|
||||||
|
|
||||||
#define PG_INITMASK() ( \
|
|
||||||
sigemptyset(&UnBlockSig), \
|
|
||||||
sigfillset(&BlockSig) \
|
|
||||||
)
|
|
||||||
#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)
|
#define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)
|
||||||
#else
|
#else
|
||||||
extern int UnBlockSig,
|
extern int UnBlockSig,
|
||||||
BlockSig;
|
BlockSig;
|
||||||
|
|
||||||
#define PG_INITMASK() ( \
|
|
||||||
UnBlockSig = 0, \
|
|
||||||
BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) | \
|
|
||||||
sigmask(SIGTERM) | sigmask(SIGALRM) | \
|
|
||||||
sigmask(SIGINT) | sigmask(SIGUSR1) | \
|
|
||||||
sigmask(SIGUSR2) | sigmask(SIGCHLD) | \
|
|
||||||
sigmask(SIGWINCH) | sigmask(SIGFPE) \
|
|
||||||
)
|
|
||||||
#define PG_SETMASK(mask) sigsetmask(*((int*)(mask)))
|
#define PG_SETMASK(mask) sigsetmask(*((int*)(mask)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void (*pqsigfunc) (int);
|
typedef void (*pqsigfunc) (int);
|
||||||
|
|
||||||
|
extern void pqinitmask(void);
|
||||||
|
|
||||||
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
|
extern pqsigfunc pqsignal(int signo, pqsigfunc func);
|
||||||
|
|
||||||
#endif /* PQSIGNAL_H */
|
#endif /* PQSIGNAL_H */
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: miscadmin.h,v 1.60 2000/06/15 00:52:04 momjian Exp $
|
* $Id: miscadmin.h,v 1.61 2000/06/28 03:32:56 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the information in this file will be moved to
|
* some of the information in this file will be moved to
|
||||||
@ -105,8 +105,6 @@ extern bool enableFsync;
|
|||||||
extern bool allowSystemTableMods;
|
extern bool allowSystemTableMods;
|
||||||
extern int SortMem;
|
extern int SortMem;
|
||||||
|
|
||||||
extern Oid LastOidProcessed; /* for query rewrite */
|
|
||||||
|
|
||||||
/* a few postmaster startup options are exported here so the
|
/* a few postmaster startup options are exported here so the
|
||||||
configuration file processor has access to them */
|
configuration file processor has access to them */
|
||||||
|
|
||||||
@ -189,9 +187,10 @@ typedef int16 ExitStatus;
|
|||||||
|
|
||||||
/* in utils/init/postinit.c */
|
/* in utils/init/postinit.c */
|
||||||
|
|
||||||
extern bool PostgresIsInitialized;
|
extern int lockingOff;
|
||||||
|
|
||||||
extern void InitPostgres(const char *dbname);
|
extern void InitPostgres(const char *dbname);
|
||||||
|
extern void BaseInit(void);
|
||||||
|
|
||||||
/* one of the ways to get out of here */
|
/* one of the ways to get out of here */
|
||||||
#define ExitPostgres(status) proc_exec(status)
|
#define ExitPostgres(status) proc_exec(status)
|
||||||
|
@ -7,100 +7,88 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: memnodes.h,v 1.16 2000/01/26 05:58:16 momjian Exp $
|
* $Id: memnodes.h,v 1.17 2000/06/28 03:33:15 tgl Exp $
|
||||||
*
|
*
|
||||||
* XXX the typedefs in this file are different from the other ???nodes.h;
|
|
||||||
* they are pointers to structures instead of the structures themselves.
|
|
||||||
* If you're wondering, this is plain laziness. I don't want to touch
|
|
||||||
* the memory context code which should be revamped altogether some day.
|
|
||||||
* - ay 10/94
|
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef MEMNODES_H
|
#ifndef MEMNODES_H
|
||||||
#define MEMNODES_H
|
#define MEMNODES_H
|
||||||
|
|
||||||
#include "lib/fstack.h"
|
|
||||||
#include "nodes/nodes.h"
|
#include "nodes/nodes.h"
|
||||||
#include "utils/memutils.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MemoryContext
|
* MemoryContext
|
||||||
* A logical context in which memory allocations occur.
|
* A logical context in which memory allocations occur.
|
||||||
*
|
*
|
||||||
* The types of memory contexts can be thought of as members of the
|
* MemoryContext itself is an abstract type that can have multiple
|
||||||
* following inheritance hierarchy with properties summarized below.
|
* implementations, though for now we have only AllocSetContext.
|
||||||
|
* The function pointers in MemoryContextMethods define one specific
|
||||||
|
* implementation of MemoryContext --- they are a virtual function table
|
||||||
|
* in C++ terms.
|
||||||
*
|
*
|
||||||
* Node
|
* Node types that are actual implementations of memory contexts must
|
||||||
* |
|
* begin with the same fields as MemoryContext.
|
||||||
* MemoryContext___
|
|
||||||
* / \
|
|
||||||
* GlobalMemory PortalMemoryContext
|
|
||||||
* / \
|
|
||||||
* PortalVariableMemory PortalHeapMemory
|
|
||||||
*
|
*
|
||||||
* Flushed at Flushed at Checkpoints
|
* Note: for largely historical reasons, typedef MemoryContext is a pointer
|
||||||
* Transaction Portal
|
* to the context struct rather than the struct type itself.
|
||||||
* Commit Close
|
|
||||||
*
|
|
||||||
* GlobalMemory n n n
|
|
||||||
* PortalVariableMemory n y n
|
|
||||||
* PortalHeapMemory y y y
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct MemoryContextMethodsData
|
typedef struct MemoryContextMethods
|
||||||
{
|
{
|
||||||
Pointer (*alloc) ();
|
void *(*alloc) (MemoryContext context, Size size);
|
||||||
void (*free_p) (); /* need to use free as a #define, so can't
|
/* call this free_p in case someone #define's free() */
|
||||||
* use free */
|
void (*free_p) (MemoryContext context, void *pointer);
|
||||||
Pointer (*realloc) ();
|
void *(*realloc) (MemoryContext context, void *pointer, Size size);
|
||||||
char *(*getName) ();
|
void (*init) (MemoryContext context);
|
||||||
void (*dump) ();
|
void (*reset) (MemoryContext context);
|
||||||
} *MemoryContextMethods;
|
void (*delete) (MemoryContext context);
|
||||||
|
void (*stats) (MemoryContext context);
|
||||||
|
} MemoryContextMethods;
|
||||||
|
|
||||||
|
|
||||||
typedef struct MemoryContextData
|
typedef struct MemoryContextData
|
||||||
{
|
{
|
||||||
NodeTag type;
|
NodeTag type; /* identifies exact kind of context */
|
||||||
MemoryContextMethods method;
|
MemoryContextMethods *methods; /* virtual function table */
|
||||||
|
MemoryContext parent; /* NULL if no parent (toplevel context) */
|
||||||
|
MemoryContext firstchild; /* head of linked list of children */
|
||||||
|
MemoryContext nextchild; /* next child of same parent */
|
||||||
|
char *name; /* context name (just for debugging) */
|
||||||
} MemoryContextData;
|
} MemoryContextData;
|
||||||
|
|
||||||
/* utils/mcxt.h contains typedef struct MemoryContextData *MemoryContext */
|
/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */
|
||||||
|
|
||||||
/* think about doing this right some time but we'll have explicit fields
|
|
||||||
for now -ay 10/94 */
|
/*
|
||||||
typedef struct GlobalMemoryData
|
* AllocSetContext is our standard implementation of MemoryContext.
|
||||||
|
*/
|
||||||
|
typedef struct AllocBlockData *AllocBlock; /* internal to aset.c */
|
||||||
|
typedef struct AllocChunkData *AllocChunk;
|
||||||
|
|
||||||
|
typedef struct AllocSetContext
|
||||||
{
|
{
|
||||||
NodeTag type;
|
MemoryContextData header; /* Standard memory-context fields */
|
||||||
MemoryContextMethods method;
|
/* Info about storage allocated in this context: */
|
||||||
AllocSetData setData;
|
AllocBlock blocks; /* head of list of blocks in this set */
|
||||||
char *name;
|
#define ALLOCSET_NUM_FREELISTS 8
|
||||||
OrderedElemData elemData;
|
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
|
||||||
} GlobalMemoryData;
|
/* 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
|
* MemoryContextIsValid
|
||||||
* True iff memory context is valid.
|
* True iff memory context is valid.
|
||||||
|
*
|
||||||
|
* Add new context types to the set accepted by this macro.
|
||||||
*/
|
*/
|
||||||
#define MemoryContextIsValid(context) \
|
#define MemoryContextIsValid(context) \
|
||||||
(IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \
|
((context) != NULL && \
|
||||||
IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory))
|
(IsA((context), AllocSetContext)))
|
||||||
|
|
||||||
|
|
||||||
#endif /* MEMNODES_H */
|
#endif /* MEMNODES_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.69 2000/06/18 22:44:31 tgl Exp $
|
* $Id: nodes.h,v 1.70 2000/06/28 03:33:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -122,10 +122,7 @@ typedef enum NodeTag
|
|||||||
*---------------------
|
*---------------------
|
||||||
*/
|
*/
|
||||||
T_MemoryContext = 400,
|
T_MemoryContext = 400,
|
||||||
T_GlobalMemory,
|
T_AllocSetContext,
|
||||||
T_PortalMemoryContext,
|
|
||||||
T_PortalVariableMemory,
|
|
||||||
T_PortalHeapMemory,
|
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
* TAGS FOR VALUE NODES (pg_list.h)
|
* TAGS FOR VALUE NODES (pg_list.h)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: geqo.h,v 1.19 2000/05/31 00:28:38 petere Exp $
|
* $Id: geqo.h,v 1.20 2000/06/28 03:33:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -65,7 +65,6 @@ extern int Geqo_random_seed; /* or negative to use current time */
|
|||||||
extern RelOptInfo *geqo(Query *root);
|
extern RelOptInfo *geqo(Query *root);
|
||||||
|
|
||||||
/* routines in geqo_eval.c */
|
/* routines in geqo_eval.c */
|
||||||
extern void geqo_eval_startup(void);
|
|
||||||
extern Cost geqo_eval(Query *root, Gene *tour, int num_gene);
|
extern Cost geqo_eval(Query *root, Gene *tour, int num_gene);
|
||||||
extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count,
|
extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count,
|
||||||
int num_gene, RelOptInfo *old_rel);
|
int num_gene, RelOptInfo *old_rel);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1995, Regents of the University of California
|
* Portions Copyright (c) 1995, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: postgres.h,v 1.41 2000/06/13 07:35:24 tgl Exp $
|
* $Id: postgres.h,v 1.42 2000/06/28 03:32:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -39,7 +39,6 @@
|
|||||||
#include "postgres_ext.h"
|
#include "postgres_ext.h"
|
||||||
#include "c.h"
|
#include "c.h"
|
||||||
#include "utils/elog.h"
|
#include "utils/elog.h"
|
||||||
#include "utils/mcxt.h"
|
|
||||||
#include "utils/palloc.h"
|
#include "utils/palloc.h"
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: shmem.h,v 1.22 2000/01/26 05:58:33 momjian Exp $
|
* $Id: shmem.h,v 1.23 2000/06/28 03:33:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -63,14 +63,13 @@ typedef struct SHM_QUEUE
|
|||||||
extern void ShmemIndexReset(void);
|
extern void ShmemIndexReset(void);
|
||||||
extern void ShmemCreate(unsigned int key, unsigned int size);
|
extern void ShmemCreate(unsigned int key, unsigned int size);
|
||||||
extern int InitShmem(unsigned int key, unsigned int size);
|
extern int InitShmem(unsigned int key, unsigned int size);
|
||||||
extern long *ShmemAlloc(unsigned long size);
|
extern void *ShmemAlloc(Size size);
|
||||||
extern int ShmemIsValid(unsigned long addr);
|
extern int ShmemIsValid(unsigned long addr);
|
||||||
extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
|
extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
|
||||||
HASHCTL *infoP, int hash_flags);
|
HASHCTL *infoP, int hash_flags);
|
||||||
extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
|
extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
|
||||||
extern SHMEM_OFFSET ShmemPIDDestroy(int pid);
|
extern SHMEM_OFFSET ShmemPIDDestroy(int pid);
|
||||||
extern long *ShmemInitStruct(char *name, unsigned long size,
|
extern void *ShmemInitStruct(char *name, Size size, bool *foundPtr);
|
||||||
bool *foundPtr);
|
|
||||||
|
|
||||||
|
|
||||||
typedef int TableID;
|
typedef int TableID;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: pquery.h,v 1.14 2000/01/26 05:58:35 momjian Exp $
|
* $Id: pquery.h,v 1.15 2000/06/28 03:33:28 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -15,20 +15,13 @@
|
|||||||
#define PQUERY_H
|
#define PQUERY_H
|
||||||
|
|
||||||
#include "executor/execdesc.h"
|
#include "executor/execdesc.h"
|
||||||
|
#include "utils/portal.h"
|
||||||
|
|
||||||
/* moved to execdesc.h
|
|
||||||
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
|
|
||||||
CommandDest dest);
|
|
||||||
|
|
||||||
*/
|
extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
|
||||||
|
|
||||||
extern EState *CreateExecutorState(void);
|
extern EState *CreateExecutorState(void);
|
||||||
|
|
||||||
|
extern Portal PreparePortal(char *portalName);
|
||||||
|
|
||||||
extern void ProcessPortal(char *portalName, Query *parseTree,
|
#endif /* PQUERY_H */
|
||||||
Plan *plan, EState *state, TupleDesc attinfo,
|
|
||||||
CommandDest dest);
|
|
||||||
|
|
||||||
extern void
|
|
||||||
ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
|
|
||||||
|
|
||||||
#endif /* pqueryIncluded */
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: tcopprot.h,v 1.30 2000/06/15 03:33:04 momjian Exp $
|
* $Id: tcopprot.h,v 1.31 2000/06/28 03:33:28 tgl Exp $
|
||||||
*
|
*
|
||||||
* OLD COMMENTS
|
* OLD COMMENTS
|
||||||
* This file was created so that other c files could get the two
|
* This file was created so that other c files could get the two
|
||||||
@ -33,12 +33,11 @@ extern bool ShowPortNumber;
|
|||||||
#ifndef BOOTSTRAP_INCLUDE
|
#ifndef BOOTSTRAP_INCLUDE
|
||||||
|
|
||||||
extern List *pg_parse_and_rewrite(char *query_string,
|
extern List *pg_parse_and_rewrite(char *query_string,
|
||||||
Oid *typev, int nargs,
|
Oid *typev, int nargs);
|
||||||
bool aclOverride);
|
|
||||||
extern Plan *pg_plan_query(Query *querytree);
|
extern Plan *pg_plan_query(Query *querytree);
|
||||||
extern void pg_exec_query_dest(char *query_string,
|
extern void pg_exec_query_dest(char *query_string,
|
||||||
CommandDest dest,
|
CommandDest dest,
|
||||||
bool aclOverride);
|
MemoryContext parse_context);
|
||||||
|
|
||||||
#endif /* BOOTSTRAP_INCLUDE */
|
#endif /* BOOTSTRAP_INCLUDE */
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: catcache.h,v 1.24 2000/06/17 04:56:29 tgl Exp $
|
* $Id: catcache.h,v 1.25 2000/06/28 03:33:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -75,8 +75,10 @@ typedef struct catcache
|
|||||||
|
|
||||||
#define InvalidCatalogCacheId (-1)
|
#define InvalidCatalogCacheId (-1)
|
||||||
|
|
||||||
extern GlobalMemory CacheCxt;
|
/* this extern duplicates utils/memutils.h... */
|
||||||
|
extern MemoryContext CacheMemoryContext;
|
||||||
|
|
||||||
|
extern void CreateCacheMemoryContext(void);
|
||||||
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
|
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
|
||||||
ItemPointer pointer);
|
ItemPointer pointer);
|
||||||
extern void ResetSystemCache(void);
|
extern void ResetSystemCache(void);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: hsearch.h,v 1.15 2000/04/12 17:16:55 momjian Exp $
|
* $Id: hsearch.h,v 1.16 2000/06/28 03:33:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -84,8 +84,7 @@ typedef struct htab
|
|||||||
char *segbase; /* segment base address for calculating
|
char *segbase; /* segment base address for calculating
|
||||||
* pointer values */
|
* pointer values */
|
||||||
SEG_OFFSET *dir; /* 'directory' of segm starts */
|
SEG_OFFSET *dir; /* 'directory' of segm starts */
|
||||||
long *(*alloc) (); /* memory allocator (long * for alignment
|
void *(*alloc) (Size); /* memory allocator */
|
||||||
* reasons) */
|
|
||||||
} HTAB;
|
} HTAB;
|
||||||
|
|
||||||
typedef struct hashctl
|
typedef struct hashctl
|
||||||
@ -99,7 +98,7 @@ typedef struct hashctl
|
|||||||
long max_dsize; /* limit to dsize if directory size is
|
long max_dsize; /* limit to dsize if directory size is
|
||||||
* limited */
|
* limited */
|
||||||
long *segbase; /* base for calculating bucket + seg ptrs */
|
long *segbase; /* base for calculating bucket + seg ptrs */
|
||||||
long *(*alloc) (); /* memory allocation function */
|
void *(*alloc) (Size); /* memory allocation function */
|
||||||
long *dir; /* directory if allocated already */
|
long *dir; /* directory if allocated already */
|
||||||
long *hctl; /* location of header information in shd
|
long *hctl; /* location of header information in shd
|
||||||
* mem */
|
* mem */
|
||||||
|
@ -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
|
* memutils.h
|
||||||
* this file contains general memory alignment, allocation
|
* This file contains declarations for memory allocation utility
|
||||||
* and manipulation stuff that used to be spread out
|
* functions. These are functions that are not quite widely used
|
||||||
* between the following files:
|
* enough to justify going in utils/palloc.h, but are still part
|
||||||
*
|
* of the API of the memory management subsystem.
|
||||||
* align.h alignment macros
|
|
||||||
* aset.h memory allocation set stuff
|
|
||||||
* oset.h (used by aset.h)
|
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: memutils.h,v 1.35 2000/05/21 02:23:28 tgl Exp $
|
* $Id: memutils.h,v 1.36 2000/06/28 03:33:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef MEMUTILS_H
|
#ifndef MEMUTILS_H
|
||||||
#define MEMUTILS_H
|
#define MEMUTILS_H
|
||||||
|
|
||||||
/* ----------------
|
#include "nodes/memnodes.h"
|
||||||
* Alignment macros: align a length or address appropriately for a given type.
|
|
||||||
*
|
|
||||||
* There used to be some incredibly crufty platform-dependent hackery here,
|
|
||||||
* but now we rely on the configure script to get the info for us. Much nicer.
|
|
||||||
*
|
|
||||||
* NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
|
|
||||||
* That case seems extremely unlikely to occur in practice, however.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
|
|
||||||
|
|
||||||
#define SHORTALIGN(LEN) TYPEALIGN(ALIGNOF_SHORT, (LEN))
|
|
||||||
#define INTALIGN(LEN) TYPEALIGN(ALIGNOF_INT, (LEN))
|
|
||||||
#define LONGALIGN(LEN) TYPEALIGN(ALIGNOF_LONG, (LEN))
|
|
||||||
#define DOUBLEALIGN(LEN) TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
|
|
||||||
#define MAXALIGN(LEN) TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* oset.h -- Fixed format ordered set definitions. *
|
|
||||||
*****************************************************************************/
|
|
||||||
/* Note:
|
|
||||||
* Fixed format ordered sets are <EXPLAIN>.
|
|
||||||
* XXX This is a preliminary version. Work is needed to explain
|
|
||||||
* XXX semantics of the external definitions. Otherwise, the
|
|
||||||
* XXX functional interface should not change.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct OrderedElemData OrderedElemData;
|
|
||||||
typedef OrderedElemData *OrderedElem;
|
|
||||||
|
|
||||||
typedef struct OrderedSetData OrderedSetData;
|
|
||||||
typedef OrderedSetData *OrderedSet;
|
|
||||||
|
|
||||||
struct OrderedElemData
|
|
||||||
{
|
|
||||||
OrderedElem next; /* Next elem or &this->set->dummy */
|
|
||||||
OrderedElem prev; /* Previous elem or &this->set->head */
|
|
||||||
OrderedSet set; /* Parent set */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OrderedSetData
|
|
||||||
{
|
|
||||||
OrderedElem head; /* First elem or &this->dummy */
|
|
||||||
OrderedElem dummy; /* (hack) Terminator == NULL */
|
|
||||||
OrderedElem tail; /* Last elem or &this->head */
|
|
||||||
Offset offset; /* Offset from struct base to elem */
|
|
||||||
/* this could be signed short int! */
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void OrderedSetInit(OrderedSet set, Offset offset);
|
|
||||||
extern Pointer OrderedSetGetHead(OrderedSet set);
|
|
||||||
extern Pointer OrderedElemGetPredecessor(OrderedElem elem);
|
|
||||||
extern Pointer OrderedElemGetSuccessor(OrderedElem elem);
|
|
||||||
extern void OrderedElemPop(OrderedElem elem);
|
|
||||||
extern void OrderedElemPushInto(OrderedElem elem, OrderedSet Set);
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* aset.h -- Allocation set definitions. *
|
|
||||||
*****************************************************************************/
|
|
||||||
/*
|
/*
|
||||||
* Description:
|
* MaxAllocSize
|
||||||
* An allocation set is a set containing allocated elements. When
|
* Arbitrary limit on size of allocations.
|
||||||
* an allocation is requested for a set, memory is allocated and a
|
|
||||||
* pointer is returned. Subsequently, this memory may be freed or
|
|
||||||
* reallocated. In addition, an allocation set may be reset which
|
|
||||||
* will cause all memory allocated within it to be freed.
|
|
||||||
*
|
|
||||||
* XXX The following material about allocation modes is all OUT OF DATE.
|
|
||||||
* aset.c currently implements only one allocation strategy,
|
|
||||||
* DynamicAllocMode, and that's the only one anyone ever requests anyway.
|
|
||||||
* If we ever did have more strategies, the new ones might or might
|
|
||||||
* not look like what is described here...
|
|
||||||
*
|
|
||||||
* Allocations may occur in four different modes. The mode of
|
|
||||||
* allocation does not affect the behavior of allocations except in
|
|
||||||
* terms of performance. The allocation mode is set at the time of
|
|
||||||
* set initialization. Once the mode is chosen, it cannot be changed
|
|
||||||
* unless the set is reinitialized.
|
|
||||||
*
|
|
||||||
* "Dynamic" mode forces all allocations to occur in a heap. This
|
|
||||||
* is a good mode to use when small memory segments are allocated
|
|
||||||
* and freed very frequently. This is a good choice when allocation
|
|
||||||
* characteristics are unknown. This is the default mode.
|
|
||||||
*
|
|
||||||
* "Static" mode attempts to allocate space as efficiently as possible
|
|
||||||
* without regard to freeing memory. This mode should be chosen only
|
|
||||||
* when it is known that many allocations will occur but that very
|
|
||||||
* little of the allocated memory will be explicitly freed.
|
|
||||||
*
|
|
||||||
* "Tunable" mode is a hybrid of dynamic and static modes. The
|
|
||||||
* tunable mode will use static mode allocation except when the
|
|
||||||
* allocation request exceeds a size limit supplied at the time of set
|
|
||||||
* initialization. "Big" objects are allocated using dynamic mode.
|
|
||||||
*
|
|
||||||
* "Bounded" mode attempts to allocate space efficiently given a limit
|
|
||||||
* on space consumed by the allocation set. This restriction can be
|
|
||||||
* considered a "soft" restriction, because memory segments will
|
|
||||||
* continue to be returned after the limit is exceeded. The limit is
|
|
||||||
* specified at the time of set initialization like for tunable mode.
|
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
* Allocation sets are not automatically reset on a system reset.
|
* There is no guarantee that allocations smaller than MaxAllocSize
|
||||||
* Higher level code is responsible for cleaning up.
|
* will succeed. Allocation requests larger than MaxAllocSize will
|
||||||
|
* be summarily denied.
|
||||||
*
|
*
|
||||||
* There may be other modes in the future.
|
* XXX This should be defined in a file of tunable constants.
|
||||||
*/
|
*/
|
||||||
|
#define MaxAllocSize ((Size) 0xfffffff) /* 16G - 1 */
|
||||||
|
|
||||||
|
#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocPointer
|
* All chunks allocated by any memory context manager are required to be
|
||||||
* Aligned pointer which may be a member of an allocation set.
|
* 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
|
* Standard top-level memory contexts.
|
||||||
* Mode of allocation for an allocation set.
|
|
||||||
*
|
*
|
||||||
* Note:
|
* Only TopMemoryContext and ErrorContext are initialized by
|
||||||
* See above for a description of the various modes.
|
* MemoryContextInit() itself.
|
||||||
*/
|
*/
|
||||||
typedef enum AllocMode
|
extern MemoryContext TopMemoryContext;
|
||||||
{
|
extern MemoryContext ErrorContext;
|
||||||
DynamicAllocMode, /* always dynamically allocate */
|
extern MemoryContext PostmasterContext;
|
||||||
StaticAllocMode, /* always "statically" allocate */
|
extern MemoryContext CacheMemoryContext;
|
||||||
TunableAllocMode, /* allocations are "tuned" */
|
extern MemoryContext QueryContext;
|
||||||
BoundedAllocMode /* allocations bounded to fixed usage */
|
extern MemoryContext TopTransactionContext;
|
||||||
} AllocMode;
|
extern MemoryContext TransactionCommandContext;
|
||||||
|
|
||||||
#define DefaultAllocMode DynamicAllocMode
|
|
||||||
|
|
||||||
typedef struct AllocSetData *AllocSet;
|
|
||||||
typedef struct AllocBlockData *AllocBlock;
|
|
||||||
typedef struct AllocChunkData *AllocChunk;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocSet
|
* Memory-context-type-independent functions in mcxt.c
|
||||||
* Allocation set.
|
|
||||||
*/
|
*/
|
||||||
typedef struct AllocSetData
|
extern void MemoryContextInit(void);
|
||||||
{
|
extern void MemoryContextReset(MemoryContext context);
|
||||||
AllocBlock blocks; /* head of list of blocks in this set */
|
extern void MemoryContextDelete(MemoryContext context);
|
||||||
#define ALLOCSET_NUM_FREELISTS 8
|
extern void MemoryContextResetChildren(MemoryContext context);
|
||||||
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
|
extern void MemoryContextDeleteChildren(MemoryContext context);
|
||||||
/* Note: this will change in the future to support other modes */
|
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
|
||||||
} AllocSetData;
|
extern void MemoryContextStats(MemoryContext context);
|
||||||
|
extern bool MemoryContextContains(MemoryContext context, void *pointer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocBlock
|
* This routine handles the context-type-independent part of memory
|
||||||
* An AllocBlock is the unit of memory that is obtained by aset.c
|
* context creation. It's intended to be called from context-type-
|
||||||
* from malloc(). It contains one or more AllocChunks, which are
|
* specific creation routines, and noplace else.
|
||||||
* 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
|
extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
|
||||||
{
|
MemoryContextMethods *methods,
|
||||||
AllocSet aset; /* aset that owns this block */
|
MemoryContext parent,
|
||||||
AllocBlock next; /* next block in aset's blocks list */
|
const char *name);
|
||||||
char *freeptr; /* start of free space in this block */
|
|
||||||
char *endptr; /* end of space in this block */
|
|
||||||
} AllocBlockData;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocChunk
|
* Memory-context-type-specific functions
|
||||||
* The prefix of each piece of memory in an AllocBlock
|
|
||||||
*/
|
*/
|
||||||
typedef struct AllocChunkData
|
|
||||||
{
|
/* aset.c */
|
||||||
/* aset is the owning aset if allocated, or the freelist link if free */
|
extern MemoryContext AllocSetContextCreate(MemoryContext parent,
|
||||||
void *aset;
|
const char *name,
|
||||||
/* size is always the size of the usable space in the chunk */
|
Size minContextSize,
|
||||||
Size size;
|
Size initBlockSize,
|
||||||
} AllocChunkData;
|
Size maxBlockSize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AllocPointerIsValid
|
* Recommended default alloc parameters, suitable for "ordinary" contexts
|
||||||
* True iff pointer is valid allocation pointer.
|
* that might hold quite a lot of data.
|
||||||
*/
|
*/
|
||||||
#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
|
#define ALLOCSET_DEFAULT_MINSIZE (8 * 1024)
|
||||||
|
#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024)
|
||||||
/*
|
#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024)
|
||||||
* 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);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* MEMUTILS_H */
|
#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
|
* palloc.h
|
||||||
* POSTGRES memory allocator definitions.
|
* POSTGRES memory allocator definitions.
|
||||||
*
|
*
|
||||||
|
* This file contains the basic memory allocation interface that is
|
||||||
|
* needed by almost every backend module. It is included directly by
|
||||||
|
* postgres.h, so the definitions here are automatically available
|
||||||
|
* everywhere. Keep it lean!
|
||||||
|
*
|
||||||
|
* Memory allocation occurs within "contexts". Every chunk obtained from
|
||||||
|
* palloc()/MemoryContextAlloc() is allocated within a specific context.
|
||||||
|
* The entire contents of a context can be freed easily and quickly by
|
||||||
|
* resetting or deleting the context --- this is both faster and less
|
||||||
|
* prone to memory-leakage bugs than releasing chunks individually.
|
||||||
|
* We organize contexts into context trees to allow fine-grain control
|
||||||
|
* over chunk lifetime while preserving the certainty that we will free
|
||||||
|
* everything that should be freed. See utils/mmgr/README for more info.
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: palloc.h,v 1.12 2000/01/26 05:58:38 momjian Exp $
|
* $Id: palloc.h,v 1.13 2000/06/28 03:33:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef PALLOC_H
|
#ifndef PALLOC_H
|
||||||
#define PALLOC_H
|
#define PALLOC_H
|
||||||
|
|
||||||
#ifdef PALLOC_IS_MALLOC
|
/*
|
||||||
|
* Type MemoryContextData is declared in nodes/memnodes.h. Most users
|
||||||
#define palloc(s) malloc(s)
|
* of memory allocation should just treat it as an abstract type, so we
|
||||||
#define pfree(p) free(p)
|
* do not provide the struct contents here.
|
||||||
#define repalloc(p,s) realloc((p),(s))
|
|
||||||
|
|
||||||
#else /* ! PALLOC_IS_MALLOC */
|
|
||||||
|
|
||||||
/* ----------
|
|
||||||
* In the case we use memory contexts, use macro's for palloc() etc.
|
|
||||||
* ----------
|
|
||||||
*/
|
*/
|
||||||
#define palloc(s) ((void *)MemoryContextAlloc(CurrentMemoryContext,(Size)(s)))
|
typedef struct MemoryContextData *MemoryContext;
|
||||||
#define pfree(p) MemoryContextFree(CurrentMemoryContext,(Pointer)(p))
|
|
||||||
#define repalloc(p,s) ((void *)MemoryContextRealloc(CurrentMemoryContext,(Pointer)(p),(Size)(s)))
|
|
||||||
|
|
||||||
#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 */
|
#endif /* PALLOC_H */
|
||||||
|
@ -7,16 +7,14 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: portal.h,v 1.23 2000/04/12 17:16:55 momjian Exp $
|
* $Id: portal.h,v 1.24 2000/06/28 03:33:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Note:
|
* Note:
|
||||||
* A portal is an abstraction which represents the execution state of
|
* A portal is an abstraction which represents the execution state of
|
||||||
* a running query (or a fixed sequence of queries). The "blank portal" is
|
* a running query (or a fixed sequence of queries).
|
||||||
* a portal with an InvalidName. This blank portal is in existance except
|
|
||||||
* between calls to BlankPortalAssignName and GetPortalByName(NULL).
|
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
* now that PQ calls can be made from within a backend, a portal
|
* now that PQ calls can be made from within a backend, a portal
|
||||||
@ -29,27 +27,18 @@
|
|||||||
#include "executor/execdesc.h"
|
#include "executor/execdesc.h"
|
||||||
#include "nodes/memnodes.h"
|
#include "nodes/memnodes.h"
|
||||||
|
|
||||||
typedef struct PortalBlockData
|
|
||||||
|
typedef struct PortalD *Portal;
|
||||||
|
|
||||||
|
typedef struct PortalD
|
||||||
{
|
{
|
||||||
AllocSetData setData;
|
char *name; /* Portal's name */
|
||||||
FixedItemData itemData;
|
MemoryContext heap; /* subsidiary memory */
|
||||||
} PortalBlockData;
|
QueryDesc *queryDesc; /* Info about query associated with portal */
|
||||||
|
|
||||||
typedef PortalBlockData *PortalBlock;
|
|
||||||
|
|
||||||
typedef struct PortalD PortalD;
|
|
||||||
typedef PortalD *Portal;
|
|
||||||
|
|
||||||
struct PortalD
|
|
||||||
{
|
|
||||||
char *name; /* XXX PortalName */
|
|
||||||
struct PortalVariableMemoryData variable;
|
|
||||||
struct PortalHeapMemoryData heap;
|
|
||||||
QueryDesc *queryDesc;
|
|
||||||
TupleDesc attinfo;
|
TupleDesc attinfo;
|
||||||
EState *state;
|
EState *state;
|
||||||
void (*cleanup) (Portal);
|
void (*cleanup) (Portal); /* Cleanup routine (optional) */
|
||||||
};
|
} PortalD;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PortalIsValid
|
* PortalIsValid
|
||||||
@ -57,36 +46,20 @@ struct PortalD
|
|||||||
*/
|
*/
|
||||||
#define PortalIsValid(p) PointerIsValid(p)
|
#define PortalIsValid(p) PointerIsValid(p)
|
||||||
|
|
||||||
/*
|
extern void EnablePortalManager(void);
|
||||||
* Special portals (well, their names anyway)
|
|
||||||
*/
|
|
||||||
#define VACPNAME "<vacuum>"
|
|
||||||
#define TRUNCPNAME "<truncate>"
|
|
||||||
|
|
||||||
extern bool PortalNameIsSpecial(char *pname);
|
|
||||||
extern void AtEOXact_portals(void);
|
extern void AtEOXact_portals(void);
|
||||||
extern void EnablePortalManager(bool on);
|
extern Portal CreatePortal(char *name);
|
||||||
|
extern void PortalDrop(Portal *portalP);
|
||||||
extern Portal GetPortalByName(char *name);
|
extern Portal GetPortalByName(char *name);
|
||||||
extern Portal BlankPortalAssignName(char *name);
|
|
||||||
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
|
extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
|
||||||
TupleDesc attinfo, EState *state,
|
TupleDesc attinfo, EState *state,
|
||||||
void (*cleanup) (Portal portal));
|
void (*cleanup) (Portal portal));
|
||||||
extern QueryDesc *PortalGetQueryDesc(Portal portal);
|
extern QueryDesc *PortalGetQueryDesc(Portal portal);
|
||||||
extern EState *PortalGetState(Portal portal);
|
extern EState *PortalGetState(Portal portal);
|
||||||
extern Portal CreatePortal(char *name);
|
extern MemoryContext PortalGetHeapMemory(Portal portal);
|
||||||
extern void PortalDrop(Portal *portalP);
|
|
||||||
extern void StartPortalAllocMode(AllocMode mode, Size limit);
|
|
||||||
extern void EndPortalAllocMode(void);
|
|
||||||
extern void PortalResetHeapMemory(Portal portal);
|
|
||||||
extern PortalVariableMemory PortalGetVariableMemory(Portal portal);
|
|
||||||
extern PortalHeapMemory PortalGetHeapMemory(Portal portal);
|
|
||||||
extern void CommonSpecialPortalOpen(void);
|
|
||||||
extern void CommonSpecialPortalClose(void);
|
|
||||||
extern PortalVariableMemory CommonSpecialPortalGetMemory(void);
|
|
||||||
extern bool CommonSpecialPortalIsOpen(void);
|
|
||||||
|
|
||||||
/* estimate of the maximum number of open portals a user would have,
|
/* estimate of the maximum number of open portals a user would have,
|
||||||
* used in initially sizing the PortalHashTable in EnablePortalManager()
|
* used in initially sizing the PortalHashTable in EnablePortalManager()
|
||||||
*/
|
*/
|
||||||
#define PORTALS_PER_USER 10
|
#define PORTALS_PER_USER 10
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user