documentation to come, but the code is all here. initdb forced.
<!--
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">
<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>
<!--
-$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
-->
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>
<!--
-$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
-->
</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">
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>FREEZE</term>
+ <listitem>
+ <para>
+ Selects aggressive <quote>freezing</quote> of tuples.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>VERBOSE</term>
<listitem>
</para>
<para>
- Plain <command>VACUUM</command> simply reclaims space and makes it
+ <command>VACUUM ANALYZE</command> performs a <command>VACUUM</command>
+ and then an <command>ANALYZE</command> for each selected table. This
+ is a handy combination form for routine maintenance scripts. See
+ <xref linkend="sql-analyze" endterm="sql-analyze-title">
+ 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 is much slower and requires an exclusive lock on each table
- while it is being processed.
+ blocks. This form 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
- is a handy combination form for routine maintenance scripts. See
- <xref linkend="sql-analyze" endterm="sql-analyze-title">
- for more details about its processing.
+ <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">
* 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 $
*
*-------------------------------------------------------------------------
*/
{
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);
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++)
{
*
*
* 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
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);
+}
* 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)
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
{
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)
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));
+}
#
#
# 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.
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' \
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" \
*
*
* 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
TupleTableSlot *slot;
ExprContext *econtext;
Snapshot snapshot;
- TransactionId XmaxRecent;
+ TransactionId OldestXmin;
/*
* sanity checks
if (IsBootstrapProcessingMode())
{
snapshot = SnapshotNow;
- XmaxRecent = InvalidTransactionId;
+ OldestXmin = InvalidTransactionId;
}
else
{
snapshot = SnapshotAny;
- GetXmaxRecent(&XmaxRecent);
+ OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared);
}
scan = heap_beginscan(heapRelation, /* relation */
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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);
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;
* 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);
/*
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);
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);
}
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 : ""));
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)
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);
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;
/* 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 */
/* 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)
{
heap_endscan(scan);
heap_close(relation, AccessShareLock);
- return HeapTupleIsValid(tuple);
+ return gottuple;
}
static bool
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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,
/*
* Start up the vacuum cleaner.
*/
- vacuum_init();
+ vacuum_init(vacstmt);
/*
* Process each selected relation. We are careful to process
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);
}
/*
* 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
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
}
+/*
+ * 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 *
* 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);
* 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 */
IsSystemRelationName(RelationGetRelationName(onerel)))
reindex = true;
- GetXmaxRecent(&XmaxRecent);
+ vacuum_set_xid_limits(vacstmt, onerel->rd_rel->relisshared,
+ &OldestXmin, &FreezeLimit);
/*
* Set up statistics-gathering machinery.
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:
/*
* 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)))))
/*
* 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
/* 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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
static int MESSAGE_LEVEL; /* message level */
-static TransactionId XmaxRecent;
+static TransactionId OldestXmin;
+static TransactionId FreezeLimit;
/* non-export function prototypes */
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));
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:
/*
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:
/*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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))
*
*
* 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
%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,
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,
*
*****************************************************************************/
-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;
}
;
n->vacuum = false;
n->analyze = true;
n->full = false;
+ n->freeze = false;
n->verbose = $2;
n->vacrel = NULL;
n->va_cols = NIL;
n->vacuum = false;
n->analyze = true;
n->full = false;
+ n->freeze = false;
n->verbose = $2;
n->vacrel = $3;
n->va_cols = $4;
| /*EMPTY*/ { $$ = FALSE; }
;
+opt_freeze: FREEZE { $$ = TRUE; }
+ | /*EMPTY*/ { $$ = FALSE; }
+ ;
+
opt_name_list: '(' name_list ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
| DROP { $$ = "drop"; }
| EACH { $$ = "each"; }
| ENCODING { $$ = "encoding"; }
+ | ENCRYPTED { $$ = "encrypted"; }
| ESCAPE { $$ = "escape"; }
| EXCLUSIVE { $$ = "exclusive"; }
| EXECUTE { $$ = "execute"; }
| TRUNCATE { $$ = "truncate"; }
| TRUSTED { $$ = "trusted"; }
| TYPE_P { $$ = "type"; }
+ | UNENCRYPTED { $$ = "unencrypted"; }
| UNLISTEN { $$ = "unlisten"; }
| UNTIL { $$ = "until"; }
| UPDATE { $$ = "update"; }
| DISTINCT { $$ = "distinct"; }
| DO { $$ = "do"; }
| ELSE { $$ = "else"; }
- | ENCRYPTED { $$ = "encrypted"; }
| END_TRANS { $$ = "end"; }
| EXCEPT { $$ = "except"; }
| EXISTS { $$ = "exists"; }
| FLOAT { $$ = "float"; }
| FOR { $$ = "for"; }
| FOREIGN { $$ = "foreign"; }
+ | FREEZE { $$ = "freeze"; }
| FROM { $$ = "from"; }
| FULL { $$ = "full"; }
| GLOBAL { $$ = "global"; }
| TRANSACTION { $$ = "transaction"; }
| TRIM { $$ = "trim"; }
| TRUE_P { $$ = "true"; }
- | UNENCRYPTED { $$ = "unencrypted"; }
| UNION { $$ = "union"; }
| UNIQUE { $$ = "unique"; }
| UNKNOWN { $$ = "unknown"; }
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{"force", FORCE},
{"foreign", FOREIGN},
{"forward", FORWARD},
+ {"freeze", FREEZE},
{"from", FROM},
{"full", FULL},
{"function", FUNCTION},
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "storage/sinval.h"
#include "storage/sinvaladt.h"
#include "utils/tqual.h"
+#include "miscadmin.h"
+
SPINLOCK SInvalLock = (SPINLOCK) NULL;
}
/*
- * 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.
+ *
+ * If allDbs is TRUE then all backends are considered; if allDbs is FALSE
+ * then only backends running in my own database are considered.
*
- * Note: we include all currently running xids in the set of considered xids.
+ * 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;
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;
}
/*----------
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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.
*
* 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?
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;
# 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 $
#
#-------------------------------------------------------------------------
$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
* 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 $
*
*-------------------------------------------------------------------------
*/
#define BootstrapTransactionId ((TransactionId) 1)
#define FrozenTransactionId ((TransactionId) 2)
#define FirstNormalTransactionId ((TransactionId) 3)
+#define MaxTransactionId ((TransactionId) 0xFFFFFFFF)
/* ----------------
* transaction ID manipulation macros
*/
#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 */
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200108241
+#define CATALOG_VERSION_NO 200108251
#endif
* 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
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));
* 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
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("");
* 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
*/
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;
* 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
* 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
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");
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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);