Transaction IDs wrap around, per my proposal of 13-Aug-01. More
documentation to come, but the code is all here. initdb forced.
This commit is contained in:
parent
d1ee78f296
commit
bc7d37a525
@ -1,6 +1,6 @@
|
||||
<!--
|
||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.21 2001/08/21 16:35:58 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.22 2001/08/26 16:55:58 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="catalogs">
|
||||
@ -840,11 +840,34 @@
|
||||
<entry><type>oid</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
Last oid in existence after the database was created; useful
|
||||
Last system OID in the database; useful
|
||||
particularly to <application>pg_dump</application>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>datvacuumxid</entry>
|
||||
<entry><type>xid</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
All tuples inserted or deleted by transaction IDs before this one
|
||||
have been marked as known committed or known aborted in this database.
|
||||
This is used to determine when commit-log space can be recycled.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>datfrozenxid</entry>
|
||||
<entry><type>xid</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
All tuples inserted by transaction IDs before this one have been
|
||||
relabeled with a permanent (<quote>frozen</>) transaction ID in this
|
||||
database. This is useful to check whether a database must be vacuumed
|
||||
soon to avoid transaction ID wraparound problems.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>datpath</entry>
|
||||
<entry><type>text</type></entry>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_database.sgml,v 1.17 2000/11/15 19:43:39 petere Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_database.sgml,v 1.18 2001/08/26 16:55:59 tgl Exp $
|
||||
Postgres documentation
|
||||
-->
|
||||
|
||||
@ -284,6 +284,20 @@ comment from Olly; response from Thomas...
|
||||
simply by setting the flag false). The <literal>template0</literal>
|
||||
database is normally marked this way to prevent modification of it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
After preparing a template database, or making any changes to one,
|
||||
it is a good idea to perform
|
||||
<command>VACUUM FREEZE</> or <command>VACUUM FULL FREEZE</> in that
|
||||
database. If this is done when there are no other open transactions
|
||||
in the same database, then it is guaranteed that all tuples in the
|
||||
database are <quote>frozen</> and will not be subject to transaction
|
||||
ID wraparound problems. This is particularly important for a database
|
||||
that will have <literal>datallowconn</literal> set to false, since it
|
||||
will be impossible to do routine maintenance <command>VACUUM</>s on
|
||||
such a database.
|
||||
See the Administrator's Guide for more information.
|
||||
</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/vacuum.sgml,v 1.17 2001/07/10 22:09:28 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/vacuum.sgml,v 1.18 2001/08/26 16:55:59 tgl Exp $
|
||||
Postgres documentation
|
||||
-->
|
||||
|
||||
@ -20,11 +20,11 @@ Postgres documentation
|
||||
</refnamediv>
|
||||
<refsynopsisdiv>
|
||||
<refsynopsisdivinfo>
|
||||
<date>2001-07-10</date>
|
||||
<date>2001-08-26</date>
|
||||
</refsynopsisdivinfo>
|
||||
<synopsis>
|
||||
VACUUM [ FULL ] [ VERBOSE ] [ <replaceable class="PARAMETER">table</replaceable> ]
|
||||
VACUUM [ FULL ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">table</replaceable> [ (<replaceable class="PARAMETER">column</replaceable> [, ...] ) ] ]
|
||||
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ <replaceable class="PARAMETER">table</replaceable> ]
|
||||
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">table</replaceable> [ (<replaceable class="PARAMETER">column</replaceable> [, ...] ) ] ]
|
||||
</synopsis>
|
||||
|
||||
<refsect2 id="R2-SQL-VACUUM-1">
|
||||
@ -46,6 +46,14 @@ VACUUM [ FULL ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">table</repl
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>FREEZE</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Selects aggressive <quote>freezing</quote> of tuples.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>VERBOSE</term>
|
||||
<listitem>
|
||||
@ -168,16 +176,6 @@ NOTICE: Index <replaceable class="PARAMETER">index</replaceable>: Pages 28;
|
||||
only that table.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Plain <command>VACUUM</command> simply reclaims space and makes it
|
||||
available for re-use. This form of the command can operate in parallel
|
||||
with normal reading and writing of the table. <command>VACUUM
|
||||
FULL</command> does more extensive processing, including moving of tuples
|
||||
across blocks to try to compact the table to the minimum number of disk
|
||||
blocks. This is much slower and requires an exclusive lock on each table
|
||||
while it is being processed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>VACUUM ANALYZE</command> performs a <command>VACUUM</command>
|
||||
and then an <command>ANALYZE</command> for each selected table. This
|
||||
@ -186,6 +184,33 @@ NOTICE: Index <replaceable class="PARAMETER">index</replaceable>: Pages 28;
|
||||
for more details about its processing.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Plain <command>VACUUM</command> (without <literal>FULL</>) simply reclaims
|
||||
space and makes it
|
||||
available for re-use. This form of the command can operate in parallel
|
||||
with normal reading and writing of the table. <command>VACUUM
|
||||
FULL</command> does more extensive processing, including moving of tuples
|
||||
across blocks to try to compact the table to the minimum number of disk
|
||||
blocks. This form is much slower and requires an exclusive lock on each
|
||||
table while it is being processed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>FREEZE</command> is a special-purpose option that
|
||||
causes tuples to be marked <quote>frozen</quote> as soon as possible,
|
||||
rather than waiting until they are quite old. If this is done when there
|
||||
are no other open transactions in the same database, then it is guaranteed
|
||||
that all tuples in the database are <quote>frozen</> and will not be
|
||||
subject to transaction ID wraparound problems, no matter how long the
|
||||
database is left un-vacuumed.
|
||||
<command>FREEZE</command> is not recommended for routine use. Its only
|
||||
intended usage is in connection with preparation of user-defined template
|
||||
databases, or other databases that are completely read-only and will not
|
||||
receive routine maintenance <command>VACUUM</> operations.
|
||||
See <xref linkend="sql-createdatabase" endterm="sql-createdatabase-title">
|
||||
for details.
|
||||
</para>
|
||||
|
||||
<refsect2 id="R2-SQL-VACUUM-3">
|
||||
<refsect2info>
|
||||
<date>2001-07-10</date>
|
||||
|
@ -13,7 +13,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.2 2001/08/25 23:24:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.3 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -762,8 +762,12 @@ ExtendCLOG(TransactionId newestXact)
|
||||
{
|
||||
int pageno;
|
||||
|
||||
/* No work except at first XID of a page */
|
||||
if (TransactionIdToPgIndex(newestXact) != 0)
|
||||
/*
|
||||
* No work except at first XID of a page. But beware: just after
|
||||
* wraparound, the first XID of page zero is FirstNormalTransactionId.
|
||||
*/
|
||||
if (TransactionIdToPgIndex(newestXact) != 0 &&
|
||||
!TransactionIdEquals(newestXact, FirstNormalTransactionId))
|
||||
return;
|
||||
|
||||
pageno = TransactionIdToPage(newestXact);
|
||||
@ -818,6 +822,18 @@ TruncateCLOG(TransactionId oldestXact)
|
||||
S_LOCK(&(ClogCtl->control_lck));
|
||||
|
||||
restart:;
|
||||
/*
|
||||
* While we are holding the lock, make an important safety check:
|
||||
* the planned cutoff point must be <= the current CLOG endpoint page.
|
||||
* Otherwise we have already wrapped around, and proceeding with the
|
||||
* truncation would risk removing the current CLOG segment.
|
||||
*/
|
||||
if (CLOGPagePrecedes(ClogCtl->latest_page_number, cutoffPage))
|
||||
{
|
||||
S_UNLOCK(&(ClogCtl->control_lck));
|
||||
elog(LOG, "unable to truncate commit log: apparent wraparound");
|
||||
return;
|
||||
}
|
||||
|
||||
for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.47 2001/08/25 18:52:41 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.48 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains the high level access-method interface to the
|
||||
@ -236,3 +236,68 @@ TransactionIdAbort(TransactionId transactionId)
|
||||
|
||||
TransactionLogUpdate(transactionId, TRANSACTION_STATUS_ABORTED);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TransactionIdPrecedes --- is id1 logically < id2?
|
||||
*/
|
||||
bool
|
||||
TransactionIdPrecedes(TransactionId id1, TransactionId id2)
|
||||
{
|
||||
/*
|
||||
* If either ID is a permanent XID then we can just do unsigned
|
||||
* comparison. If both are normal, do a modulo-2^31 comparison.
|
||||
*/
|
||||
int32 diff;
|
||||
|
||||
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
||||
return (id1 < id2);
|
||||
|
||||
diff = (int32) (id1 - id2);
|
||||
return (diff < 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
|
||||
*/
|
||||
bool
|
||||
TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
|
||||
{
|
||||
int32 diff;
|
||||
|
||||
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
||||
return (id1 <= id2);
|
||||
|
||||
diff = (int32) (id1 - id2);
|
||||
return (diff <= 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* TransactionIdFollows --- is id1 logically > id2?
|
||||
*/
|
||||
bool
|
||||
TransactionIdFollows(TransactionId id1, TransactionId id2)
|
||||
{
|
||||
int32 diff;
|
||||
|
||||
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
||||
return (id1 > id2);
|
||||
|
||||
diff = (int32) (id1 - id2);
|
||||
return (diff > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* TransactionIdFollowsOrEquals --- is id1 logically >= id2?
|
||||
*/
|
||||
bool
|
||||
TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
|
||||
{
|
||||
int32 diff;
|
||||
|
||||
if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
|
||||
return (id1 >= id2);
|
||||
|
||||
diff = (int32) (id1 - id2);
|
||||
return (diff >= 0);
|
||||
}
|
||||
|
@ -6,23 +6,18 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: xid.c,v 1.32 2001/08/23 23:06:37 tgl Exp $
|
||||
*
|
||||
* OLD COMMENTS
|
||||
* XXX WARNING
|
||||
* Much of this file will change when we change our representation
|
||||
* of transaction ids -cim 3/23/90
|
||||
*
|
||||
* It is time to make the switch from 5 byte to 4 byte transaction ids
|
||||
* This file was totally reworked. -mer 5/22/92
|
||||
* $Id: xid.c,v 1.33 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "access/xact.h"
|
||||
|
||||
|
||||
#define PG_GETARG_TRANSACTIONID(n) DatumGetTransactionId(PG_GETARG_DATUM(n))
|
||||
#define PG_RETURN_TRANSACTIONID(x) return TransactionIdGetDatum(x)
|
||||
|
||||
@ -30,9 +25,9 @@
|
||||
Datum
|
||||
xidin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *representation = PG_GETARG_CSTRING(0);
|
||||
char *str = PG_GETARG_CSTRING(0);
|
||||
|
||||
PG_RETURN_TRANSACTIONID((TransactionId) atol(representation));
|
||||
PG_RETURN_TRANSACTIONID((TransactionId) strtoul(str, NULL, 0));
|
||||
}
|
||||
|
||||
Datum
|
||||
@ -40,21 +35,15 @@ xidout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
|
||||
/* maximum 32 bit unsigned integer representation takes 10 chars */
|
||||
char *representation = palloc(11);
|
||||
char *str = palloc(11);
|
||||
|
||||
snprintf(representation, 11, "%lu", (unsigned long) transactionId);
|
||||
snprintf(str, 11, "%lu", (unsigned long) transactionId);
|
||||
|
||||
PG_RETURN_CSTRING(representation);
|
||||
PG_RETURN_CSTRING(str);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* xideq
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* xideq - returns 1, iff xid1 == xid2
|
||||
* 0 else;
|
||||
* xideq - are two xids equal?
|
||||
*/
|
||||
Datum
|
||||
xideq(PG_FUNCTION_ARGS)
|
||||
@ -64,3 +53,19 @@ xideq(PG_FUNCTION_ARGS)
|
||||
|
||||
PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
|
||||
}
|
||||
|
||||
/*
|
||||
* xid_age - compute age of an XID (relative to current xact)
|
||||
*/
|
||||
Datum
|
||||
xid_age(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TransactionId xid = PG_GETARG_TRANSACTIONID(0);
|
||||
TransactionId now = GetCurrentTransactionId();
|
||||
|
||||
/* Permanent XIDs are always infinitely old */
|
||||
if (! TransactionIdIsNormal(xid))
|
||||
PG_RETURN_INT32(INT_MAX);
|
||||
|
||||
PG_RETURN_INT32((int32) (now - xid));
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.22 2001/08/24 14:07:48 petere Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.23 2001/08/26 16:55:59 tgl Exp $
|
||||
#
|
||||
# NOTES
|
||||
# non-essential whitespace is removed from the generated file.
|
||||
@ -155,12 +155,14 @@ INDEXMAXKEYS4=`expr $INDEXMAXKEYS '*' 4` || exit
|
||||
touch ${OUTPUT_PREFIX}.description.$$
|
||||
|
||||
# ----------------
|
||||
# strip comments and trash from .h before we generate
|
||||
# the .bki file...
|
||||
# Strip comments and other trash from .h
|
||||
#
|
||||
# Put multi-line start/end comments on a separate line
|
||||
#
|
||||
# Rename datatypes that have different names in .h files than in SQL
|
||||
#
|
||||
# Substitute values of configuration constants
|
||||
# ----------------
|
||||
# also, change Oid to oid. -- AY 8/94.
|
||||
# also, change NameData to name. -- jolly 8/21/95.
|
||||
# put multi-line start/end comments on a separate line
|
||||
#
|
||||
cat $INFILES | \
|
||||
sed -e 's;/\*.*\*/;;g' \
|
||||
@ -173,11 +175,14 @@ sed -e 's;/\*.*\*/;;g' \
|
||||
sed -e "s/;[ ]*$//g" \
|
||||
-e "s/^[ ]*//" \
|
||||
-e "s/[ ]Oid/ oid/g" \
|
||||
-e "s/[ ]NameData/ name/g" \
|
||||
-e "s/^Oid/oid/g" \
|
||||
-e "s/(Oid/(oid/g" \
|
||||
-e "s/[ ]NameData/ name/g" \
|
||||
-e "s/^NameData/name/g" \
|
||||
-e "s/(NameData/(name/g" \
|
||||
-e "s/(Oid/(oid/g" \
|
||||
-e "s/[ ]TransactionId/ xid/g" \
|
||||
-e "s/^TransactionId/xid/g" \
|
||||
-e "s/(TransactionId/(xid/g" \
|
||||
-e "s/NAMEDATALEN/$NAMEDATALEN/g" \
|
||||
-e "s/DEFAULT_ATTSTATTARGET/$DEFAULTATTSTATTARGET/g" \
|
||||
-e "s/INDEX_MAX_KEYS\*2/$INDEXMAXKEYS2/g" \
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.162 2001/08/22 18:24:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.163 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -1692,7 +1692,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
TupleTableSlot *slot;
|
||||
ExprContext *econtext;
|
||||
Snapshot snapshot;
|
||||
TransactionId XmaxRecent;
|
||||
TransactionId OldestXmin;
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
@ -1731,12 +1731,12 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
if (IsBootstrapProcessingMode())
|
||||
{
|
||||
snapshot = SnapshotNow;
|
||||
XmaxRecent = InvalidTransactionId;
|
||||
OldestXmin = InvalidTransactionId;
|
||||
}
|
||||
else
|
||||
{
|
||||
snapshot = SnapshotAny;
|
||||
GetXmaxRecent(&XmaxRecent);
|
||||
OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
|
||||
}
|
||||
|
||||
scan = heap_beginscan(heapRelation, /* relation */
|
||||
@ -1769,7 +1769,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
|
||||
sv_infomask = heapTuple->t_data->t_infomask;
|
||||
|
||||
switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, XmaxRecent))
|
||||
switch (HeapTupleSatisfiesVacuum(heapTuple->t_data, OldestXmin))
|
||||
{
|
||||
case HEAPTUPLE_DEAD:
|
||||
indexIt = false;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.78 2001/08/10 18:57:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.79 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -39,8 +39,9 @@
|
||||
|
||||
/* non-export function prototypes */
|
||||
static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
int *encodingP, bool *dbIsTemplateP,
|
||||
Oid *dbLastSysOidP, char *dbpath);
|
||||
int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
|
||||
TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
|
||||
char *dbpath);
|
||||
static bool get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb);
|
||||
static char *resolve_alt_dbpath(const char *dbpath, Oid dboid);
|
||||
static bool remove_dbdirs(const char *real_loc, const char *altloc);
|
||||
@ -65,6 +66,8 @@ createdb(const char *dbname, const char *dbpath,
|
||||
int src_encoding;
|
||||
bool src_istemplate;
|
||||
Oid src_lastsysoid;
|
||||
TransactionId src_vacuumxid;
|
||||
TransactionId src_frozenxid;
|
||||
char src_dbpath[MAXPGPATH];
|
||||
Relation pg_database_rel;
|
||||
HeapTuple tuple;
|
||||
@ -91,7 +94,7 @@ createdb(const char *dbname, const char *dbpath,
|
||||
* idea, so accept possibility of race to create. We will check again
|
||||
* after we grab the exclusive lock.
|
||||
*/
|
||||
if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
elog(ERROR, "CREATE DATABASE: database \"%s\" already exists", dbname);
|
||||
|
||||
/*
|
||||
@ -101,7 +104,9 @@ createdb(const char *dbname, const char *dbpath,
|
||||
dbtemplate = "template1"; /* Default template database name */
|
||||
|
||||
if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
|
||||
&src_istemplate, &src_lastsysoid, src_dbpath))
|
||||
&src_istemplate, &src_lastsysoid,
|
||||
&src_vacuumxid, &src_frozenxid,
|
||||
src_dbpath))
|
||||
elog(ERROR, "CREATE DATABASE: template \"%s\" does not exist",
|
||||
dbtemplate);
|
||||
|
||||
@ -208,8 +213,10 @@ createdb(const char *dbname, const char *dbpath,
|
||||
pg_database_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
|
||||
/* Check to see if someone else created same DB name meanwhile. */
|
||||
if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
/* Don't hold lock while doing recursive remove */
|
||||
heap_close(pg_database_rel, AccessExclusiveLock);
|
||||
remove_dbdirs(nominal_loc, alt_loc);
|
||||
elog(ERROR, "CREATE DATABASE: database \"%s\" already exists", dbname);
|
||||
}
|
||||
@ -227,6 +234,8 @@ createdb(const char *dbname, const char *dbpath,
|
||||
new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
|
||||
new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
|
||||
new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
|
||||
new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
|
||||
new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
|
||||
/* no nulls here, GetRawDatabaseInfo doesn't like them */
|
||||
new_record[Anum_pg_database_datpath - 1] =
|
||||
DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
|
||||
@ -307,7 +316,7 @@ dropdb(const char *dbname)
|
||||
pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
|
||||
|
||||
if (!get_db_info(dbname, &db_id, &db_owner, NULL,
|
||||
&db_istemplate, NULL, dbpath))
|
||||
&db_istemplate, NULL, NULL, NULL, dbpath))
|
||||
elog(ERROR, "DROP DATABASE: database \"%s\" does not exist", dbname);
|
||||
|
||||
if (!use_super && GetUserId() != db_owner)
|
||||
@ -397,13 +406,15 @@ dropdb(const char *dbname)
|
||||
|
||||
static bool
|
||||
get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
int *encodingP, bool *dbIsTemplateP,
|
||||
Oid *dbLastSysOidP, char *dbpath)
|
||||
int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
|
||||
TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
|
||||
char *dbpath)
|
||||
{
|
||||
Relation relation;
|
||||
ScanKeyData scanKey;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
bool gottuple;
|
||||
|
||||
AssertArg(name);
|
||||
|
||||
@ -414,12 +425,11 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
F_NAMEEQ, NameGetDatum(name));
|
||||
|
||||
scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scanKey);
|
||||
if (!HeapScanIsValid(scan))
|
||||
elog(ERROR, "Cannot begin scan of %s", DatabaseRelationName);
|
||||
|
||||
tuple = heap_getnext(scan, 0);
|
||||
|
||||
if (HeapTupleIsValid(tuple))
|
||||
gottuple = HeapTupleIsValid(tuple);
|
||||
if (gottuple)
|
||||
{
|
||||
Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
|
||||
text *tmptext;
|
||||
@ -428,7 +438,7 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
/* oid of the database */
|
||||
if (dbIdP)
|
||||
*dbIdP = tuple->t_data->t_oid;
|
||||
/* uid of the owner */
|
||||
/* sysid of the owner */
|
||||
if (ownerIdP)
|
||||
*ownerIdP = dbform->datdba;
|
||||
/* multibyte encoding */
|
||||
@ -440,6 +450,12 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
/* last system OID used in database */
|
||||
if (dbLastSysOidP)
|
||||
*dbLastSysOidP = dbform->datlastsysoid;
|
||||
/* limit of vacuumed XIDs */
|
||||
if (dbVacuumXidP)
|
||||
*dbVacuumXidP = dbform->datvacuumxid;
|
||||
/* limit of frozen XIDs */
|
||||
if (dbFrozenXidP)
|
||||
*dbFrozenXidP = dbform->datfrozenxid;
|
||||
/* database path (as registered in pg_database) */
|
||||
if (dbpath)
|
||||
{
|
||||
@ -462,7 +478,7 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
heap_endscan(scan);
|
||||
heap_close(relation, AccessShareLock);
|
||||
|
||||
return HeapTupleIsValid(tuple);
|
||||
return gottuple;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -13,7 +13,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.207 2001/08/10 18:57:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.208 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -21,11 +21,13 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "access/clog.h"
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/xlog.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_index.h"
|
||||
#include "commands/vacuum.h"
|
||||
#include "executor/executor.h"
|
||||
@ -108,15 +110,24 @@ static MemoryContext vac_context = NULL;
|
||||
|
||||
static int MESSAGE_LEVEL; /* message level */
|
||||
|
||||
static TransactionId XmaxRecent;
|
||||
static TransactionId OldestXmin;
|
||||
static TransactionId FreezeLimit;
|
||||
|
||||
static TransactionId initialOldestXmin;
|
||||
static TransactionId initialFreezeLimit;
|
||||
|
||||
|
||||
/* non-export function prototypes */
|
||||
static void vacuum_init(void);
|
||||
static void vacuum_shutdown(void);
|
||||
static void vacuum_init(VacuumStmt *vacstmt);
|
||||
static void vacuum_shutdown(VacuumStmt *vacstmt);
|
||||
static VRelList getrels(Name VacRelP, const char *stmttype);
|
||||
static void vac_update_dbstats(Oid dbid,
|
||||
TransactionId vacuumXID,
|
||||
TransactionId frozenXID);
|
||||
static void vac_truncate_clog(TransactionId vacuumXID,
|
||||
TransactionId frozenXID);
|
||||
static void vacuum_rel(Oid relid, VacuumStmt *vacstmt);
|
||||
static void full_vacuum_rel(Relation onerel);
|
||||
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
|
||||
static void scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages);
|
||||
static void repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
@ -213,7 +224,7 @@ vacuum(VacuumStmt *vacstmt)
|
||||
/*
|
||||
* Start up the vacuum cleaner.
|
||||
*/
|
||||
vacuum_init();
|
||||
vacuum_init(vacstmt);
|
||||
|
||||
/*
|
||||
* Process each selected relation. We are careful to process
|
||||
@ -230,21 +241,8 @@ vacuum(VacuumStmt *vacstmt)
|
||||
analyze_rel(cur->vrl_relid, vacstmt);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we did a complete vacuum, then flush the init file that relcache.c
|
||||
* uses to save startup time. The next backend startup will rebuild the
|
||||
* init file with up-to-date information from pg_class. This lets the
|
||||
* optimizer see the stats that we've collected for certain critical
|
||||
* system indexes. See relcache.c for more details.
|
||||
*
|
||||
* Ignore any failure to unlink the file, since it might not be there if
|
||||
* no backend has been started since the last vacuum.
|
||||
*/
|
||||
if (vacstmt->vacrel == NULL)
|
||||
unlink(RELCACHE_INIT_FILENAME);
|
||||
|
||||
/* clean up */
|
||||
vacuum_shutdown();
|
||||
vacuum_shutdown(vacstmt);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -268,20 +266,68 @@ vacuum(VacuumStmt *vacstmt)
|
||||
* PostgresMain().
|
||||
*/
|
||||
static void
|
||||
vacuum_init(void)
|
||||
vacuum_init(VacuumStmt *vacstmt)
|
||||
{
|
||||
if (vacstmt->vacuum && vacstmt->vacrel == NULL)
|
||||
{
|
||||
/*
|
||||
* Compute the initially applicable OldestXmin and FreezeLimit XIDs,
|
||||
* so that we can record these values at the end of the VACUUM.
|
||||
* Note that individual tables may well be processed with newer values,
|
||||
* but we can guarantee that no (non-shared) relations are processed
|
||||
* with older ones.
|
||||
*
|
||||
* It is okay to record non-shared values in pg_database, even though
|
||||
* we may vacuum shared relations with older cutoffs, because only
|
||||
* the minimum of the values present in pg_database matters. We
|
||||
* can be sure that shared relations have at some time been vacuumed
|
||||
* with cutoffs no worse than the global minimum; for, if there is
|
||||
* a backend in some other DB with xmin = OLDXMIN that's determining
|
||||
* the cutoff with which we vacuum shared relations, it is not possible
|
||||
* for that database to have a cutoff newer than OLDXMIN recorded in
|
||||
* pg_database.
|
||||
*/
|
||||
vacuum_set_xid_limits(vacstmt, false,
|
||||
&initialOldestXmin, &initialFreezeLimit);
|
||||
}
|
||||
|
||||
/* matches the StartTransaction in PostgresMain() */
|
||||
CommitTransactionCommand();
|
||||
}
|
||||
|
||||
static void
|
||||
vacuum_shutdown(void)
|
||||
vacuum_shutdown(VacuumStmt *vacstmt)
|
||||
{
|
||||
/* on entry, we are not in a transaction */
|
||||
|
||||
/* matches the CommitTransaction in PostgresMain() */
|
||||
StartTransactionCommand();
|
||||
|
||||
/*
|
||||
* If we did a database-wide VACUUM, update the database's pg_database
|
||||
* row with info about the transaction IDs used, and try to truncate
|
||||
* pg_clog.
|
||||
*/
|
||||
if (vacstmt->vacuum && vacstmt->vacrel == NULL)
|
||||
{
|
||||
vac_update_dbstats(MyDatabaseId,
|
||||
initialOldestXmin, initialFreezeLimit);
|
||||
vac_truncate_clog(initialOldestXmin, initialFreezeLimit);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we did a complete vacuum or analyze, then flush the init file that
|
||||
* relcache.c uses to save startup time. The next backend startup will
|
||||
* rebuild the init file with up-to-date information from pg_class.
|
||||
* This lets the optimizer see the stats that we've collected for certain
|
||||
* critical system indexes. See relcache.c for more details.
|
||||
*
|
||||
* Ignore any failure to unlink the file, since it might not be there if
|
||||
* no backend has been started since the last vacuum.
|
||||
*/
|
||||
if (vacstmt->vacrel == NULL)
|
||||
unlink(RELCACHE_INIT_FILENAME);
|
||||
|
||||
/*
|
||||
* Clean up working storage --- note we must do this after
|
||||
* StartTransactionCommand, else we might be trying to delete the
|
||||
@ -382,6 +428,52 @@ getrels(Name VacRelP, const char *stmttype)
|
||||
return vrl;
|
||||
}
|
||||
|
||||
/*
|
||||
* vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points
|
||||
*/
|
||||
void
|
||||
vacuum_set_xid_limits(VacuumStmt *vacstmt, bool sharedRel,
|
||||
TransactionId *oldestXmin,
|
||||
TransactionId *freezeLimit)
|
||||
{
|
||||
TransactionId limit;
|
||||
|
||||
*oldestXmin = GetOldestXmin(sharedRel);
|
||||
|
||||
Assert(TransactionIdIsNormal(*oldestXmin));
|
||||
|
||||
if (vacstmt->freeze)
|
||||
{
|
||||
/* FREEZE option: use oldest Xmin as freeze cutoff too */
|
||||
limit = *oldestXmin;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Normal case: freeze cutoff is well in the past, to wit, about
|
||||
* halfway to the wrap horizon
|
||||
*/
|
||||
limit = GetCurrentTransactionId() - (MaxTransactionId >> 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Be careful not to generate a "permanent" XID
|
||||
*/
|
||||
if (!TransactionIdIsNormal(limit))
|
||||
limit = FirstNormalTransactionId;
|
||||
|
||||
/*
|
||||
* Ensure sane relationship of limits
|
||||
*/
|
||||
if (TransactionIdFollows(limit, *oldestXmin))
|
||||
{
|
||||
elog(NOTICE, "oldest Xmin is far in the past --- close open transactions soon to avoid wraparound problems");
|
||||
limit = *oldestXmin;
|
||||
}
|
||||
|
||||
*freezeLimit = limit;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vac_update_relstats() -- update statistics for one relation
|
||||
@ -449,6 +541,122 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vac_update_dbstats() -- update statistics for one database
|
||||
*
|
||||
* Update the whole-database statistics that are kept in its pg_database
|
||||
* row.
|
||||
*
|
||||
* We violate no-overwrite semantics here by storing new values for the
|
||||
* statistics columns directly into the tuple that's already on the page.
|
||||
* As with vac_update_relstats, this avoids leaving dead tuples behind
|
||||
* after a VACUUM; which is good since GetRawDatabaseInfo
|
||||
* can get confused by finding dead tuples in pg_database.
|
||||
*
|
||||
* This routine is shared by full and lazy VACUUM. Note that it is only
|
||||
* applied after a database-wide VACUUM operation.
|
||||
*/
|
||||
static void
|
||||
vac_update_dbstats(Oid dbid,
|
||||
TransactionId vacuumXID,
|
||||
TransactionId frozenXID)
|
||||
{
|
||||
Relation relation;
|
||||
ScanKeyData entry[1];
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
Form_pg_database dbform;
|
||||
|
||||
relation = heap_openr(DatabaseRelationName, RowExclusiveLock);
|
||||
|
||||
/* Must use a heap scan, since there's no syscache for pg_database */
|
||||
ScanKeyEntryInitialize(&entry[0], 0x0,
|
||||
ObjectIdAttributeNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(dbid));
|
||||
|
||||
scan = heap_beginscan(relation, 0, SnapshotNow, 1, entry);
|
||||
|
||||
tuple = heap_getnext(scan, 0);
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "database %u does not exist", dbid);
|
||||
|
||||
dbform = (Form_pg_database) GETSTRUCT(tuple);
|
||||
|
||||
/* overwrite the existing statistics in the tuple */
|
||||
dbform->datvacuumxid = vacuumXID;
|
||||
dbform->datfrozenxid = frozenXID;
|
||||
|
||||
/* invalidate the tuple in the cache and write the buffer */
|
||||
RelationInvalidateHeapTuple(relation, tuple);
|
||||
WriteNoReleaseBuffer(scan->rs_cbuf);
|
||||
|
||||
heap_endscan(scan);
|
||||
|
||||
heap_close(relation, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vac_truncate_clog() -- attempt to truncate the commit log
|
||||
*
|
||||
* Scan pg_database to determine the system-wide oldest datvacuumxid,
|
||||
* and use it to truncate the transaction commit log (pg_clog).
|
||||
* Also generate a warning if the system-wide oldest datfrozenxid
|
||||
* seems to be in danger of wrapping around.
|
||||
*
|
||||
* The passed XIDs are simply the ones I just wrote into my pg_database
|
||||
* entry. They're used to initialize the "min" calculations.
|
||||
*
|
||||
* This routine is shared by full and lazy VACUUM. Note that it is only
|
||||
* applied after a database-wide VACUUM operation.
|
||||
*/
|
||||
static void
|
||||
vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
|
||||
{
|
||||
Relation relation;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
int32 age;
|
||||
|
||||
relation = heap_openr(DatabaseRelationName, AccessShareLock);
|
||||
|
||||
scan = heap_beginscan(relation, 0, SnapshotNow, 0, NULL);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
|
||||
|
||||
/* Ignore non-connectable databases (eg, template0) */
|
||||
/* It's assumed that these have been frozen correctly */
|
||||
if (!dbform->datallowconn)
|
||||
continue;
|
||||
|
||||
if (TransactionIdIsNormal(dbform->datvacuumxid) &&
|
||||
TransactionIdPrecedes(dbform->datvacuumxid, vacuumXID))
|
||||
vacuumXID = dbform->datvacuumxid;
|
||||
if (TransactionIdIsNormal(dbform->datfrozenxid) &&
|
||||
TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
|
||||
frozenXID = dbform->datfrozenxid;
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
|
||||
heap_close(relation, AccessShareLock);
|
||||
|
||||
/* Truncate CLOG to the oldest vacuumxid */
|
||||
TruncateCLOG(vacuumXID);
|
||||
|
||||
/* Give warning about impending wraparound problems */
|
||||
age = (int32) (GetCurrentTransactionId() - frozenXID);
|
||||
if (age > (int32) ((MaxTransactionId >> 3) * 3))
|
||||
elog(NOTICE, "Some databases have not been vacuumed in %d transactions."
|
||||
"\n\tBetter vacuum them within %d transactions,"
|
||||
"\n\tor you may have a wraparound failure.",
|
||||
age, (int32) (MaxTransactionId >> 1) - age);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Code common to both flavors of VACUUM *
|
||||
@ -550,7 +758,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
* Do the actual work --- either FULL or "lazy" vacuum
|
||||
*/
|
||||
if (vacstmt->full)
|
||||
full_vacuum_rel(onerel);
|
||||
full_vacuum_rel(onerel, vacstmt);
|
||||
else
|
||||
lazy_vacuum_rel(onerel, vacstmt);
|
||||
|
||||
@ -597,7 +805,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
* and locked the relation.
|
||||
*/
|
||||
static void
|
||||
full_vacuum_rel(Relation onerel)
|
||||
full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
||||
{
|
||||
VacPageListData vacuum_pages; /* List of pages to vacuum and/or
|
||||
* clean indexes */
|
||||
@ -613,7 +821,8 @@ full_vacuum_rel(Relation onerel)
|
||||
IsSystemRelationName(RelationGetRelationName(onerel)))
|
||||
reindex = true;
|
||||
|
||||
GetXmaxRecent(&XmaxRecent);
|
||||
vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
|
||||
&OldestXmin, &FreezeLimit);
|
||||
|
||||
/*
|
||||
* Set up statistics-gathering machinery.
|
||||
@ -845,12 +1054,25 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
tupgone = false;
|
||||
sv_infomask = tuple.t_data->t_infomask;
|
||||
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, XmaxRecent))
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin))
|
||||
{
|
||||
case HEAPTUPLE_DEAD:
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
break;
|
||||
case HEAPTUPLE_LIVE:
|
||||
/*
|
||||
* Tuple is good. Consider whether to replace its xmin
|
||||
* value with FrozenTransactionId.
|
||||
*/
|
||||
if (TransactionIdIsNormal(tuple.t_data->t_xmin) &&
|
||||
TransactionIdPrecedes(tuple.t_data->t_xmin,
|
||||
FreezeLimit))
|
||||
{
|
||||
tuple.t_data->t_xmin = FrozenTransactionId;
|
||||
tuple.t_data->t_infomask &= ~HEAP_XMIN_INVALID;
|
||||
tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED;
|
||||
pgchanged = true;
|
||||
}
|
||||
break;
|
||||
case HEAPTUPLE_RECENTLY_DEAD:
|
||||
/*
|
||||
@ -1312,7 +1534,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
* tuples to another places.
|
||||
*/
|
||||
if ((tuple.t_data->t_infomask & HEAP_UPDATED &&
|
||||
!TransactionIdPrecedes(tuple.t_data->t_xmin, XmaxRecent)) ||
|
||||
!TransactionIdPrecedes(tuple.t_data->t_xmin, OldestXmin)) ||
|
||||
(!(tuple.t_data->t_infomask & HEAP_XMAX_INVALID) &&
|
||||
!(ItemPointerEquals(&(tuple.t_self),
|
||||
&(tuple.t_data->t_ctid)))))
|
||||
@ -1362,7 +1584,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
|
||||
/*
|
||||
* This means that in the middle of chain there
|
||||
* was tuple updated by older (than XmaxRecent)
|
||||
* was tuple updated by older (than OldestXmin)
|
||||
* xaction and this tuple is already deleted by
|
||||
* me. Actually, upper part of chain should be
|
||||
* removed and seems that this should be handled
|
||||
@ -1430,7 +1652,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
|
||||
/* All done ? */
|
||||
if (!(tp.t_data->t_infomask & HEAP_UPDATED) ||
|
||||
TransactionIdPrecedes(tp.t_data->t_xmin, XmaxRecent))
|
||||
TransactionIdPrecedes(tp.t_data->t_xmin, OldestXmin))
|
||||
break;
|
||||
|
||||
/* Well, try to find tuple with old row version */
|
||||
|
@ -31,7 +31,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.4 2001/08/10 18:57:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.5 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -94,7 +94,8 @@ typedef struct LVRelStats
|
||||
|
||||
static int MESSAGE_LEVEL; /* message level */
|
||||
|
||||
static TransactionId XmaxRecent;
|
||||
static TransactionId OldestXmin;
|
||||
static TransactionId FreezeLimit;
|
||||
|
||||
|
||||
/* non-export function prototypes */
|
||||
@ -143,7 +144,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
||||
else
|
||||
MESSAGE_LEVEL = DEBUG;
|
||||
|
||||
GetXmaxRecent(&XmaxRecent);
|
||||
vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
|
||||
&OldestXmin, &FreezeLimit);
|
||||
|
||||
vacrelstats = (LVRelStats *) palloc(sizeof(LVRelStats));
|
||||
MemSet(vacrelstats, 0, sizeof(LVRelStats));
|
||||
@ -307,12 +309,25 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
tupgone = false;
|
||||
sv_infomask = tuple.t_data->t_infomask;
|
||||
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, XmaxRecent))
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin))
|
||||
{
|
||||
case HEAPTUPLE_DEAD:
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
break;
|
||||
case HEAPTUPLE_LIVE:
|
||||
/*
|
||||
* Tuple is good. Consider whether to replace its xmin
|
||||
* value with FrozenTransactionId.
|
||||
*/
|
||||
if (TransactionIdIsNormal(tuple.t_data->t_xmin) &&
|
||||
TransactionIdPrecedes(tuple.t_data->t_xmin,
|
||||
FreezeLimit))
|
||||
{
|
||||
tuple.t_data->t_xmin = FrozenTransactionId;
|
||||
tuple.t_data->t_infomask &= ~HEAP_XMIN_INVALID;
|
||||
tuple.t_data->t_infomask |= HEAP_XMIN_COMMITTED;
|
||||
pgchanged = true;
|
||||
}
|
||||
break;
|
||||
case HEAPTUPLE_RECENTLY_DEAD:
|
||||
/*
|
||||
@ -783,12 +798,13 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
|
||||
tupgone = false;
|
||||
sv_infomask = tuple.t_data->t_infomask;
|
||||
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, XmaxRecent))
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin))
|
||||
{
|
||||
case HEAPTUPLE_DEAD:
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
break;
|
||||
case HEAPTUPLE_LIVE:
|
||||
/* Shouldn't be necessary to re-freeze anything */
|
||||
break;
|
||||
case HEAPTUPLE_RECENTLY_DEAD:
|
||||
/*
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.154 2001/08/21 16:36:02 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.155 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2246,6 +2246,7 @@ _copyVacuumStmt(VacuumStmt *from)
|
||||
newnode->vacuum = from->vacuum;
|
||||
newnode->full = from->full;
|
||||
newnode->analyze = from->analyze;
|
||||
newnode->freeze = from->freeze;
|
||||
newnode->verbose = from->verbose;
|
||||
if (from->vacrel)
|
||||
newnode->vacrel = pstrdup(from->vacrel);
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.102 2001/08/21 16:36:02 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.103 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1116,6 +1116,8 @@ _equalVacuumStmt(VacuumStmt *a, VacuumStmt *b)
|
||||
return false;
|
||||
if (a->analyze != b->analyze)
|
||||
return false;
|
||||
if (a->freeze != b->freeze)
|
||||
return false;
|
||||
if (a->verbose != b->verbose)
|
||||
return false;
|
||||
if (!equalstr(a->vacrel, b->vacrel))
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.248 2001/08/25 18:52:41 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.249 2001/08/26 16:55:59 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -215,7 +215,7 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
%type <boolean> opt_binary, opt_using, opt_instead, opt_cursor
|
||||
%type <boolean> opt_with_copy, index_opt_unique, opt_verbose, opt_full
|
||||
%type <boolean> analyze_keyword
|
||||
%type <boolean> opt_freeze, analyze_keyword
|
||||
|
||||
%type <ival> copy_dirn, direction, reindex_type, drop_type,
|
||||
opt_column, event, comment_type, comment_cl,
|
||||
@ -346,7 +346,7 @@ static void doNegateFloat(Value *v);
|
||||
CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
|
||||
DATABASE, DELIMITERS, DO,
|
||||
EACH, ENCODING, EXCLUSIVE, EXPLAIN,
|
||||
FORCE, FORWARD, FUNCTION, HANDLER,
|
||||
FORCE, FORWARD, FREEZE, FUNCTION, HANDLER,
|
||||
ILIKE, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
|
||||
LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P,
|
||||
MAXVALUE, MINVALUE, MODE, MOVE,
|
||||
@ -3082,34 +3082,37 @@ ClusterStmt: CLUSTER index_name ON relation_name
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
VacuumStmt: VACUUM opt_full opt_verbose
|
||||
VacuumStmt: VACUUM opt_full opt_freeze opt_verbose
|
||||
{
|
||||
VacuumStmt *n = makeNode(VacuumStmt);
|
||||
n->vacuum = true;
|
||||
n->analyze = false;
|
||||
n->full = $2;
|
||||
n->verbose = $3;
|
||||
n->freeze = $3;
|
||||
n->verbose = $4;
|
||||
n->vacrel = NULL;
|
||||
n->va_cols = NIL;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| VACUUM opt_full opt_verbose relation_name
|
||||
| VACUUM opt_full opt_freeze opt_verbose relation_name
|
||||
{
|
||||
VacuumStmt *n = makeNode(VacuumStmt);
|
||||
n->vacuum = true;
|
||||
n->analyze = false;
|
||||
n->full = $2;
|
||||
n->verbose = $3;
|
||||
n->vacrel = $4;
|
||||
n->freeze = $3;
|
||||
n->verbose = $4;
|
||||
n->vacrel = $5;
|
||||
n->va_cols = NIL;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| VACUUM opt_full opt_verbose AnalyzeStmt
|
||||
| VACUUM opt_full opt_freeze opt_verbose AnalyzeStmt
|
||||
{
|
||||
VacuumStmt *n = (VacuumStmt *) $4;
|
||||
VacuumStmt *n = (VacuumStmt *) $5;
|
||||
n->vacuum = true;
|
||||
n->full = $2;
|
||||
n->verbose |= $3;
|
||||
n->freeze = $3;
|
||||
n->verbose |= $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
@ -3120,6 +3123,7 @@ AnalyzeStmt: analyze_keyword opt_verbose
|
||||
n->vacuum = false;
|
||||
n->analyze = true;
|
||||
n->full = false;
|
||||
n->freeze = false;
|
||||
n->verbose = $2;
|
||||
n->vacrel = NULL;
|
||||
n->va_cols = NIL;
|
||||
@ -3131,6 +3135,7 @@ AnalyzeStmt: analyze_keyword opt_verbose
|
||||
n->vacuum = false;
|
||||
n->analyze = true;
|
||||
n->full = false;
|
||||
n->freeze = false;
|
||||
n->verbose = $2;
|
||||
n->vacrel = $3;
|
||||
n->va_cols = $4;
|
||||
@ -3150,6 +3155,10 @@ opt_full: FULL { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
;
|
||||
|
||||
opt_freeze: FREEZE { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
;
|
||||
|
||||
opt_name_list: '(' name_list ')' { $$ = $2; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
;
|
||||
@ -5615,6 +5624,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; }
|
||||
| DROP { $$ = "drop"; }
|
||||
| EACH { $$ = "each"; }
|
||||
| ENCODING { $$ = "encoding"; }
|
||||
| ENCRYPTED { $$ = "encrypted"; }
|
||||
| ESCAPE { $$ = "escape"; }
|
||||
| EXCLUSIVE { $$ = "exclusive"; }
|
||||
| EXECUTE { $$ = "execute"; }
|
||||
@ -5693,6 +5703,7 @@ TokenId: ABSOLUTE { $$ = "absolute"; }
|
||||
| TRUNCATE { $$ = "truncate"; }
|
||||
| TRUSTED { $$ = "trusted"; }
|
||||
| TYPE_P { $$ = "type"; }
|
||||
| UNENCRYPTED { $$ = "unencrypted"; }
|
||||
| UNLISTEN { $$ = "unlisten"; }
|
||||
| UNTIL { $$ = "until"; }
|
||||
| UPDATE { $$ = "update"; }
|
||||
@ -5753,7 +5764,6 @@ ColLabel: ColId { $$ = $1; }
|
||||
| DISTINCT { $$ = "distinct"; }
|
||||
| DO { $$ = "do"; }
|
||||
| ELSE { $$ = "else"; }
|
||||
| ENCRYPTED { $$ = "encrypted"; }
|
||||
| END_TRANS { $$ = "end"; }
|
||||
| EXCEPT { $$ = "except"; }
|
||||
| EXISTS { $$ = "exists"; }
|
||||
@ -5763,6 +5773,7 @@ ColLabel: ColId { $$ = $1; }
|
||||
| FLOAT { $$ = "float"; }
|
||||
| FOR { $$ = "for"; }
|
||||
| FOREIGN { $$ = "foreign"; }
|
||||
| FREEZE { $$ = "freeze"; }
|
||||
| FROM { $$ = "from"; }
|
||||
| FULL { $$ = "full"; }
|
||||
| GLOBAL { $$ = "global"; }
|
||||
@ -5825,7 +5836,6 @@ ColLabel: ColId { $$ = $1; }
|
||||
| TRANSACTION { $$ = "transaction"; }
|
||||
| TRIM { $$ = "trim"; }
|
||||
| TRUE_P { $$ = "true"; }
|
||||
| UNENCRYPTED { $$ = "unencrypted"; }
|
||||
| UNION { $$ = "union"; }
|
||||
| UNIQUE { $$ = "unique"; }
|
||||
| UNKNOWN { $$ = "unknown"; }
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.96 2001/08/16 20:38:54 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.97 2001/08/26 16:56:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -118,6 +118,7 @@ static ScanKeyword ScanKeywords[] = {
|
||||
{"force", FORCE},
|
||||
{"foreign", FOREIGN},
|
||||
{"forward", FORWARD},
|
||||
{"freeze", FREEZE},
|
||||
{"from", FROM},
|
||||
{"full", FULL},
|
||||
{"function", FUNCTION},
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.39 2001/08/25 18:52:42 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.40 2001/08/26 16:56:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -20,6 +20,8 @@
|
||||
#include "storage/sinval.h"
|
||||
#include "storage/sinvaladt.h"
|
||||
#include "utils/tqual.h"
|
||||
#include "miscadmin.h"
|
||||
|
||||
|
||||
SPINLOCK SInvalLock = (SPINLOCK) NULL;
|
||||
|
||||
@ -210,17 +212,23 @@ TransactionIdIsInProgress(TransactionId xid)
|
||||
}
|
||||
|
||||
/*
|
||||
* GetXmaxRecent -- returns oldest transaction that was running
|
||||
* when all current transaction were started.
|
||||
* It's used by vacuum to decide what deleted
|
||||
* tuples must be preserved in a table.
|
||||
* GetOldestXmin -- returns oldest transaction that was running
|
||||
* when any current transaction was started.
|
||||
*
|
||||
* Note: we include all currently running xids in the set of considered xids.
|
||||
* If allDbs is TRUE then all backends are considered; if allDbs is FALSE
|
||||
* then only backends running in my own database are considered.
|
||||
*
|
||||
* This is used by VACUUM to decide which deleted tuples must be preserved
|
||||
* in a table. allDbs = TRUE is needed for shared relations, but allDbs =
|
||||
* FALSE is sufficient for non-shared relations, since only backends in my
|
||||
* own database could ever see the tuples in them.
|
||||
*
|
||||
* Note: we include the currently running xids in the set of considered xids.
|
||||
* This ensures that if a just-started xact has not yet set its snapshot,
|
||||
* when it does set the snapshot it cannot set xmin less than what we compute.
|
||||
*/
|
||||
void
|
||||
GetXmaxRecent(TransactionId *XmaxRecent)
|
||||
TransactionId
|
||||
GetOldestXmin(bool allDbs)
|
||||
{
|
||||
SISeg *segP = shmInvalBuffer;
|
||||
ProcState *stateP = segP->procState;
|
||||
@ -238,24 +246,28 @@ GetXmaxRecent(TransactionId *XmaxRecent)
|
||||
if (pOffset != INVALID_OFFSET)
|
||||
{
|
||||
PROC *proc = (PROC *) MAKE_PTR(pOffset);
|
||||
/* Fetch xid just once - see GetNewTransactionId */
|
||||
TransactionId xid = proc->xid;
|
||||
|
||||
if (TransactionIdIsNormal(xid))
|
||||
if (allDbs || proc->databaseId == MyDatabaseId)
|
||||
{
|
||||
if (TransactionIdPrecedes(xid, result))
|
||||
result = xid;
|
||||
xid = proc->xmin;
|
||||
/* Fetch xid just once - see GetNewTransactionId */
|
||||
TransactionId xid = proc->xid;
|
||||
|
||||
if (TransactionIdIsNormal(xid))
|
||||
{
|
||||
if (TransactionIdPrecedes(xid, result))
|
||||
result = xid;
|
||||
xid = proc->xmin;
|
||||
if (TransactionIdIsNormal(xid))
|
||||
if (TransactionIdPrecedes(xid, result))
|
||||
result = xid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpinRelease(SInvalLock);
|
||||
|
||||
*XmaxRecent = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*----------
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.41 2001/08/25 18:52:42 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.42 2001/08/26 16:56:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -592,8 +592,8 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot)
|
||||
* HeapTupleSatisfiesVacuum - determine tuple status for VACUUM and related
|
||||
* operations
|
||||
*
|
||||
* XmaxRecent is a cutoff XID (obtained from GetXmaxRecent()). Tuples
|
||||
* deleted by XIDs >= XmaxRecent are deemed "recently dead"; they might
|
||||
* OldestXmin is a cutoff XID (obtained from GetOldestXmin()). Tuples
|
||||
* deleted by XIDs >= OldestXmin are deemed "recently dead"; they might
|
||||
* still be visible to some open transaction, so we can't remove them,
|
||||
* even if we see that the deleting transaction has committed.
|
||||
*
|
||||
@ -603,7 +603,7 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot)
|
||||
* change in t_infomask and scheduling a disk write if so.
|
||||
*/
|
||||
HTSV_Result
|
||||
HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId XmaxRecent)
|
||||
HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin)
|
||||
{
|
||||
/*
|
||||
* Has inserting transaction committed?
|
||||
@ -712,7 +712,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId XmaxRecent)
|
||||
return HEAPTUPLE_DEAD;
|
||||
}
|
||||
|
||||
if (!TransactionIdPrecedes(tuple->t_xmax, XmaxRecent))
|
||||
if (!TransactionIdPrecedes(tuple->t_xmax, OldestXmin))
|
||||
{
|
||||
/* deleting xact is too recent, tuple could still be visible */
|
||||
return HEAPTUPLE_RECENTLY_DEAD;
|
||||
|
@ -27,7 +27,7 @@
|
||||
# Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
# Portions Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.134 2001/08/25 18:52:42 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.135 2001/08/26 16:56:00 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@ -841,7 +841,7 @@ echo "ok"
|
||||
$ECHO_N "vacuuming database template1... "$ECHO_C
|
||||
|
||||
"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
|
||||
VACUUM FULL ANALYZE;
|
||||
VACUUM FULL FREEZE;
|
||||
EOF
|
||||
if [ "$?" -ne 0 ]; then
|
||||
exit_nicely
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: transam.h,v 1.39 2001/08/25 18:52:42 tgl Exp $
|
||||
* $Id: transam.h,v 1.40 2001/08/26 16:56:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -31,6 +31,7 @@
|
||||
#define BootstrapTransactionId ((TransactionId) 1)
|
||||
#define FrozenTransactionId ((TransactionId) 2)
|
||||
#define FirstNormalTransactionId ((TransactionId) 3)
|
||||
#define MaxTransactionId ((TransactionId) 0xFFFFFFFF)
|
||||
|
||||
/* ----------------
|
||||
* transaction ID manipulation macros
|
||||
@ -38,11 +39,7 @@
|
||||
*/
|
||||
#define TransactionIdIsValid(xid) ((xid) != InvalidTransactionId)
|
||||
#define TransactionIdIsNormal(xid) ((xid) >= FirstNormalTransactionId)
|
||||
#define TransactionIdEquals(id1, id2) ((id1) == (id2))
|
||||
#define TransactionIdPrecedes(id1, id2) ((id1) < (id2))
|
||||
#define TransactionIdPrecedesOrEquals(id1, id2) ((id1) <= (id2))
|
||||
#define TransactionIdFollows(id1, id2) ((id1) > (id2))
|
||||
#define TransactionIdFollowsOrEquals(id1, id2) ((id1) >= (id2))
|
||||
#define TransactionIdEquals(id1, id2) ((id1) == (id2))
|
||||
#define TransactionIdStore(xid, dest) (*(dest) = (xid))
|
||||
#define StoreInvalidTransactionId(dest) (*(dest) = InvalidTransactionId)
|
||||
/* advance a transaction ID variable, handling wraparound correctly */
|
||||
@ -105,6 +102,10 @@ extern bool TransactionIdDidCommit(TransactionId transactionId);
|
||||
extern bool TransactionIdDidAbort(TransactionId transactionId);
|
||||
extern void TransactionIdCommit(TransactionId transactionId);
|
||||
extern void TransactionIdAbort(TransactionId transactionId);
|
||||
extern bool TransactionIdPrecedes(TransactionId id1, TransactionId id2);
|
||||
extern bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2);
|
||||
extern bool TransactionIdFollows(TransactionId id1, TransactionId id2);
|
||||
extern bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2);
|
||||
|
||||
/* in transam/varsup.c */
|
||||
extern TransactionId GetNewTransactionId(void);
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: xact.h,v 1.35 2001/08/25 18:52:42 tgl Exp $
|
||||
* $Id: xact.h,v 1.36 2001/08/26 16:56:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -130,5 +130,6 @@ extern void xact_desc(char *buf, uint8 xl_info, char *rec);
|
||||
extern Datum xidin(PG_FUNCTION_ARGS);
|
||||
extern Datum xidout(PG_FUNCTION_ARGS);
|
||||
extern Datum xideq(PG_FUNCTION_ARGS);
|
||||
extern Datum xid_age(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif /* XACT_H */
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catversion.h,v 1.92 2001/08/25 18:52:42 tgl Exp $
|
||||
* $Id: catversion.h,v 1.93 2001/08/26 16:56:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200108241
|
||||
#define CATALOG_VERSION_NO 200108251
|
||||
|
||||
#endif
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_attribute.h,v 1.75 2001/08/25 18:52:42 tgl Exp $
|
||||
* $Id: pg_attribute.h,v 1.76 2001/08/26 16:56:00 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
@ -276,8 +276,10 @@ DATA(insert ( 1262 encoding 23 0 4 3 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1262 datistemplate 16 0 1 4 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1262 datallowconn 16 0 1 5 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1262 datlastsysoid 26 0 4 6 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1262 datvacuumxid 28 0 4 7 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1262 datfrozenxid 28 0 4 8 0 -1 -1 t p f i f f));
|
||||
/* do not mark datpath as toastable; GetRawDatabaseInfo won't cope */
|
||||
DATA(insert ( 1262 datpath 25 0 -1 7 0 -1 -1 f p f i f f));
|
||||
DATA(insert ( 1262 datpath 25 0 -1 9 0 -1 -1 f p f i f f));
|
||||
DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p f i f f));
|
||||
DATA(insert ( 1262 oid 26 0 4 -2 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1262 xmin 28 0 4 -3 0 -1 -1 t p f i f f));
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_class.h,v 1.53 2001/08/25 18:52:43 tgl Exp $
|
||||
* $Id: pg_class.h,v 1.54 2001/08/26 16:56:01 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
@ -142,7 +142,7 @@ DATA(insert OID = 1260 ( pg_shadow 86 PGUID 0 1260 0 0 0 0 f t r 8 0 0 0 0 0
|
||||
DESCR("");
|
||||
DATA(insert OID = 1261 ( pg_group 87 PGUID 0 1261 0 0 0 0 f t r 3 0 0 0 0 0 f f f f _null_ ));
|
||||
DESCR("");
|
||||
DATA(insert OID = 1262 ( pg_database 88 PGUID 0 1262 0 0 0 0 f t r 7 0 0 0 0 0 t f f f _null_ ));
|
||||
DATA(insert OID = 1262 ( pg_database 88 PGUID 0 1262 0 0 0 0 f t r 9 0 0 0 0 0 t f f f _null_ ));
|
||||
DESCR("");
|
||||
DATA(insert OID = 376 ( pg_xactlock 0 PGUID 0 0 0 0 0 0 f t s 1 0 0 0 0 0 f f f f _null_ ));
|
||||
DESCR("");
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_database.h,v 1.17 2001/03/22 04:00:38 momjian Exp $
|
||||
* $Id: pg_database.h,v 1.18 2001/08/26 16:56:02 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
@ -33,13 +33,14 @@
|
||||
*/
|
||||
CATALOG(pg_database) BOOTSTRAP
|
||||
{
|
||||
NameData datname;
|
||||
int4 datdba;
|
||||
int4 encoding;
|
||||
bool datistemplate; /* allowed as template for CREATE
|
||||
* DATABASE? */
|
||||
NameData datname; /* database name */
|
||||
int4 datdba; /* sysid of owner */
|
||||
int4 encoding; /* multibyte encoding, if any */
|
||||
bool datistemplate; /* allowed as CREATE DATABASE template? */
|
||||
bool datallowconn; /* new connections allowed? */
|
||||
Oid datlastsysoid;
|
||||
Oid datlastsysoid; /* highest OID to consider a system OID */
|
||||
TransactionId datvacuumxid; /* all XIDs before this are vacuumed */
|
||||
TransactionId datfrozenxid; /* all XIDs before this are frozen */
|
||||
text datpath; /* VARIABLE LENGTH FIELD */
|
||||
} FormData_pg_database;
|
||||
|
||||
@ -54,16 +55,18 @@ typedef FormData_pg_database *Form_pg_database;
|
||||
* compiler constants for pg_database
|
||||
* ----------------
|
||||
*/
|
||||
#define Natts_pg_database 7
|
||||
#define Natts_pg_database 9
|
||||
#define Anum_pg_database_datname 1
|
||||
#define Anum_pg_database_datdba 2
|
||||
#define Anum_pg_database_encoding 3
|
||||
#define Anum_pg_database_datistemplate 4
|
||||
#define Anum_pg_database_datallowconn 5
|
||||
#define Anum_pg_database_datlastsysoid 6
|
||||
#define Anum_pg_database_datpath 7
|
||||
#define Anum_pg_database_datvacuumxid 7
|
||||
#define Anum_pg_database_datfrozenxid 8
|
||||
#define Anum_pg_database_datpath 9
|
||||
|
||||
DATA(insert OID = 1 ( template1 PGUID ENCODING t t 0 "" ));
|
||||
DATA(insert OID = 1 ( template1 PGUID ENCODING t t 0 0 0 "" ));
|
||||
DESCR("Default template database");
|
||||
|
||||
#define TemplateDbOid 1
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_proc.h,v 1.206 2001/08/16 20:38:54 tgl Exp $
|
||||
* $Id: pg_proc.h,v 1.207 2001/08/26 16:56:02 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
@ -1450,6 +1450,8 @@ DATA(insert OID = 1179 ( date PGUID 12 f t f t 1 f 1082 "702" 100 0 0 100
|
||||
DESCR("convert abstime to date");
|
||||
DATA(insert OID = 1180 ( abstime PGUID 12 f t f t 1 f 702 "1184" 100 0 0 100 timestamp_abstime - ));
|
||||
DESCR("convert timestamp to abstime");
|
||||
DATA(insert OID = 1181 ( age PGUID 12 f t f t 1 f 23 "28" 100 0 0 100 xid_age - ));
|
||||
DESCR("age of a transaction ID, in transactions before current transaction");
|
||||
|
||||
DATA(insert OID = 1188 ( timestamp_mi PGUID 12 f t f t 2 f 1186 "1184 1184" 100 0 0 100 timestamp_mi - ));
|
||||
DESCR("subtract");
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: vacuum.h,v 1.39 2001/07/18 00:46:25 tgl Exp $
|
||||
* $Id: vacuum.h,v 1.40 2001/08/26 16:56:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -44,6 +44,9 @@ extern void vac_update_relstats(Oid relid,
|
||||
BlockNumber num_pages,
|
||||
double num_tuples,
|
||||
bool hasindex);
|
||||
extern void vacuum_set_xid_limits(VacuumStmt *vacstmt, bool sharedRel,
|
||||
TransactionId *oldestXmin,
|
||||
TransactionId *freezeLimit);
|
||||
extern bool vac_is_partial_index(Relation indrel);
|
||||
extern void vac_init_rusage(VacRUsage *ru0);
|
||||
extern const char *vac_show_rusage(VacRUsage *ru0);
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parsenodes.h,v 1.142 2001/08/21 16:36:06 tgl Exp $
|
||||
* $Id: parsenodes.h,v 1.143 2001/08/26 16:56:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -694,6 +694,7 @@ typedef struct VacuumStmt
|
||||
bool vacuum; /* do VACUUM step */
|
||||
bool full; /* do FULL (non-concurrent) vacuum */
|
||||
bool analyze; /* do ANALYZE step */
|
||||
bool freeze; /* early-freeze option */
|
||||
bool verbose; /* print progress info */
|
||||
char *vacrel; /* name of single table to process, or NULL */
|
||||
List *va_cols; /* list of column names, or NIL for all */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: sinval.h,v 1.20 2001/07/06 21:04:26 tgl Exp $
|
||||
* $Id: sinval.h,v 1.21 2001/08/26 16:56:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -76,7 +76,7 @@ extern void ReceiveSharedInvalidMessages(
|
||||
|
||||
extern bool DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself);
|
||||
extern bool TransactionIdIsInProgress(TransactionId xid);
|
||||
extern void GetXmaxRecent(TransactionId *XmaxRecent);
|
||||
extern TransactionId GetOldestXmin(bool allDbs);
|
||||
extern int CountActiveBackends(void);
|
||||
/* Use "struct proc", not PROC, to avoid including proc.h here */
|
||||
extern struct proc *BackendIdGetProc(BackendId procId);
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: tqual.h,v 1.33 2001/08/23 23:06:38 tgl Exp $
|
||||
* $Id: tqual.h,v 1.34 2001/08/26 16:56:03 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -104,7 +104,7 @@ extern bool HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple,
|
||||
Snapshot snapshot);
|
||||
extern int HeapTupleSatisfiesUpdate(HeapTuple tuple);
|
||||
extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTupleHeader tuple,
|
||||
TransactionId XmaxRecent);
|
||||
TransactionId OldestXmin);
|
||||
|
||||
extern Snapshot GetSnapshotData(bool serializable);
|
||||
extern void SetQuerySnapshot(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user