Transaction IDs wrap around, per my proposal of 13-Aug-01. More
authorTom Lane
Sun, 26 Aug 2001 16:56:03 +0000 (16:56 +0000)
committerTom Lane
Sun, 26 Aug 2001 16:56:03 +0000 (16:56 +0000)
documentation to come, but the code is all here.  initdb forced.

29 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/create_database.sgml
doc/src/sgml/ref/vacuum.sgml
src/backend/access/transam/clog.c
src/backend/access/transam/transam.c
src/backend/access/transam/xid.c
src/backend/catalog/genbki.sh
src/backend/catalog/index.c
src/backend/commands/dbcommands.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/storage/ipc/sinval.c
src/backend/utils/time/tqual.c
src/bin/initdb/initdb.sh
src/include/access/transam.h
src/include/access/xact.h
src/include/catalog/catversion.h
src/include/catalog/pg_attribute.h
src/include/catalog/pg_class.h
src/include/catalog/pg_database.h
src/include/catalog/pg_proc.h
src/include/commands/vacuum.h
src/include/nodes/parsenodes.h
src/include/storage/sinval.h
src/include/utils/tqual.h

index e2c3139d8534237bd9d13f8452f8942f1b74fc36..39c05e24bd8193056af42341e3b4646d0412cb69 100644 (file)
@@ -1,6 +1,6 @@
 
 
 
       oid
       
       
-       Last oid in existence after the database was created; useful
+       Last system OID in the database; useful
        particularly to pg_dump
       
      
 
+     
+      datvacuumxid
+      xid
+      
+      
+       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.
+      
+     
+
+     
+      datfrozenxid
+      xid
+      
+      
+       All tuples inserted by transaction IDs before this one have been
+       relabeled with a permanent (frozen) transaction ID in this
+       database.  This is useful to check whether a database must be vacuumed
+       soon to avoid transaction ID wraparound problems.
+      
+     
+
      
       datpath
       text
index e128c1891d0f097cadee4d51da2859ce196d2495..20477ac191c269038f39352cdd2f296b2b0deb9f 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -284,6 +284,20 @@ comment from Olly; response from Thomas...
    simply by setting the flag false).  The template0
    database is normally marked this way to prevent modification of it.
   
+
+  
+   After preparing a template database, or making any changes to one,
+   it is a good idea to perform
+   VACUUM FREEZE or 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 frozen and will not be subject to transaction
+   ID wraparound problems.  This is particularly important for a database
+   that will have datallowconn set to false, since it
+   will be impossible to do routine maintenance VACUUMs on
+   such a database.
+    See the Administrator's Guide for more information.
+  
   
  
 
index e8374725b34bd3cc8e98d224ca092a866bd6f5ec..62e47a7086dc2f9e0a2b18a36317b94d9e07c7da 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -20,11 +20,11 @@ Postgres documentation
  
  
   
-   2001-07-10
+   2001-08-26
   
   
-VACUUM [ FULL ] [ VERBOSE ] [ table ]
-VACUUM [ FULL ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
+VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ table ]
+VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
   
 
   
@@ -46,6 +46,14 @@ VACUUM [ FULL ] [ VERBOSE ] ANALYZE [ table
        
       
      
+     
+      FREEZE
+      
+       
+        Selects aggressive freezing of tuples.
+       
+      
+     
      
       VERBOSE
       
@@ -169,21 +177,38 @@ NOTICE:  Index index: Pages 28;
   
 
   
-   Plain VACUUM simply reclaims space and makes it
+   VACUUM ANALYZE performs a VACUUM
+   and then an ANALYZE for each selected table.  This
+   is a handy combination form for routine maintenance scripts.  See
+   
+   for more details about its processing.
+  
+
+  
+   Plain VACUUM (without 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.  VACUUM
    FULL 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.
   
 
   
-   VACUUM ANALYZE performs a VACUUM
-   and then an ANALYZE for each selected table.  This
-   is a handy combination form for routine maintenance scripts.  See
-   
-   for more details about its processing.
+   FREEZE is a special-purpose option that
+   causes tuples to be marked frozen 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 frozen and will not be
+   subject to transaction ID wraparound problems, no matter how long the
+   database is left un-vacuumed.
+   FREEZE 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 VACUUM operations.
+   See 
+   for details.
   
 
   
index 07581e4444a875e08f562e9f89bdd49fff966135..a403838bd792ec086f1a517db5bea8b3604728f7 100644 (file)
@@ -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++)
    {
index 3364ed66337b9b709defd09c31b2d45f1cb8a066..2a73c045b76ad069ac8940fc4cf56f1fcff85b78 100644 (file)
@@ -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);
+}
index 689fc33ceaff5d65edec367f860e1a29af5ee372..babe7c9a48bfcad032e480ca8a3f0446dfa2fb8b 100644 (file)
@@ -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 
+
 #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));
+}
index 3d51423af426b0e920bf42e8ec4dc87d9928d710..25c8d7d2d4d3873c27be82feeeae4f731720c2d6 100644 (file)
@@ -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" \
index f11b3d9f31921909ccfcf59416e8359bbb6bda20..9debf84cab4385692936b221f7e68342eba3856a 100644 (file)
@@ -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;
index b20525e77d949ea63f0ad23549c7d400f5b53c34..f7f765d9d7a0b70284d13eb6ad25cf664fc18e7b 100644 (file)
@@ -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
index 9a9d90fa2cf1e5b8bd95e0dab2dcc017c19b5bb7..fe72ff96020f3d0e1c5c94e32d0007d3dab6aa34 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 #include 
 
+#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 */
index bdde6114133b14b4857de5b721699ba2219a6e1f..f525ecaf36c609bfafad2d1b767bd27d0259b517 100644 (file)
@@ -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:
                    /*
index 26da8d479370eb68696652447a5032a873d691d2..cf9ad2e983c5967e3984ff11b4b277806547e115 100644 (file)
@@ -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);
index c2cd2109fe97f9025a7642a989bfaae24aebdd58..9dce1f61b46111754d4b03cd5b4dc06b10578a08 100644 (file)
@@ -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))
index 84ef63e6295e51517a9a6b23fe26e292be65dfc2..8d5e9abb07d9ff6844ddcc4c383168e7e630ceb5 100644 (file)
@@ -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     opt_binary, opt_using, opt_instead, opt_cursor
 %type     opt_with_copy, index_opt_unique, opt_verbose, opt_full
-%type     analyze_keyword
+%type     opt_freeze, analyze_keyword
 
 %type    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"; }
index 5c1427da03ec5c645c4c715d6146ab6f78d3b7d3..bff257a545522c64c4507a2c0179b8120a745f95 100644 (file)
@@ -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},
index 985577c4a6c571c32985bf6f3b51432328fa67b5..1d43b1ead4476274032b5b2b64e8ab411ef2acd5 100644 (file)
@@ -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.
+ *
+ * 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;
@@ -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;
 }
 
 /*----------
index 5f5699c4458e9e5179c72c9805f76bbe72ff9970..f0536d761186ef318f3e8d4c836ad32e81fe6ce1 100644 (file)
@@ -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;
index bbb014391a489498d19a6998737aadc79c7d409b..11799e7049074fc440d307e555816a23ed21f217 100644 (file)
@@ -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 <
-VACUUM FULL ANALYZE;
+VACUUM FULL FREEZE;
 EOF
 if [ "$?" -ne 0 ]; then
     exit_nicely
index f0d213361ac73a8689c6fd7149262e02a14ab1a8..5ce62d289f980790596749374aca69ab133a63c4 100644 (file)
@@ -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
  */
 #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);
index a9c7b674a95a22e48882bceb2995912b15ac1a11..55c043511778e8edaa455808baa430c2fbb05f28 100644 (file)
@@ -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 */
index 58d43a652931c6fd76dfacb96299123152ceb38a..0b67a37ad22aedd311ee827cd62f35f67f5b0a28 100644 (file)
@@ -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
index eb1ba77235e87365d54ab4d173e17151ebed7add..826d2b8ea849517029f29797398d269ec21572de 100644 (file)
@@ -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));
index 4f2708e3bd08f045126bc72beb4a609de5176e16..2d0103a87b8397aa8ca117887018e548c3d94c1c 100644 (file)
@@ -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("");
index ffc83da3b4cfc7ccd08dbcc9c896660d0b1ca82b..f3e0fbd99b7ba0072d3ac393e180849d5117e42a 100644 (file)
@@ -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
  */
 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
index e2a48dec681fea3550cfa7ed0687ec576a77668d..c8919ff683314111ef9f3bce33c051d868787cc8 100644 (file)
@@ -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");
index 0d362bb1801ef58a960f5968b44c9f71bc304877..5d1541ef3ba233f9f9f3467f8786b0a15ba6da46 100644 (file)
@@ -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);
index a961cb5af4f85781a0eae36e5659acc4435c2897..315ad113ee766c5a1e53a5575f084e1aa2a47f5a 100644 (file)
@@ -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 */
index 11aad6095738d8d3f2f151a00d79e4e318eb9a05..2e1ac7bfb155bcfa824e94877c3184cd487fcc5b 100644 (file)
@@ -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);
index bff437f540bd7d9211b230a5135c90bbac8793e9..cc238e7457bd0a4f13987da69bb62587a8af9b3c 100644 (file)
@@ -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);