On Thu, Jul 14, 2005 at 10:52:56AM -0400, Tom Lane wrote:
> I've applied Alvaro's latest integrated-autovacuum patch.  There are
> still a number of loose ends to be dealt with before beta, though:

Ok, here's a patch that deals with some of this:

- The stat collector is modified so as to keep shared relations separate
  from regular ones.  Also, backends sends messages separately.
  Autovacuum takes advantage of this, so it correctly identifies the
  appropiate time to operate on a shared relation, irrespective of the
  database where they were modified.  Note however that it uses each
  database's pg_autovacuum settings.  This means it could be vacuumed
  sooner in one database than another, but I don't think it's a problem.

- Temp tables are completely ignored.

- pg_statistic is completely ignored.

- databases with no stat entry are still ignored, except that they are
  checked for Xid wraparound like any other.  The "oldest" one is chosen
  for vacuum in a particular autovacuum run.

- A database-wide vacuum forces a pg_database flat-file update, so that
  the wraparound check actually works.

- The postmaster's main loop sleeps Min(60, autovacuum_naptime), in
  order to be able to pick naptimes smaller than 60 seconds.  In order
  not to make the loop a busy-wait, I forced a minimum of 1 to that GUC
  var.



Some comments:

- Now that we have a real Xid wraparound check, we could go back to
  having any table with no stat entry ignored, which was the original
  coding.  There's no danger of wraparound, and there'd be no work done
  to a table that doesn't have any activity.  We have to consider what
  happens at stat reset -- AFAICS there's no problem, because as soon as
  the table sees some activity, it will be picked up by pgstat.
  However, it would be bad if stats are reset right after some heavy
  activity on a table.  Maybe the only thing we need is documentation.

- datallowcon is still ignored.  Now it's safe to do so, because we have
  a real Xid wraparound check.  Changing it requires extending the
  pg_database flat-file (should be fairly easy).

- There are stat messages emitted for a database-wide vacuum, just like
  any other.  This means that all tables in the database would end up in
  pgstat; and also all databases, including those with datallowconn = false.
  This may not be good.  I'm not sure what exactly to do about it.  Do
  we want to disallow such stats?  Disable message sending (or
  collecting) in some circumstances?

- I haven't done anything yet w.r.t. the custom vacuum_delay nor sleep
  scale factor.

- There are still no docs.


-- 
Alvaro Herrera (<alvherre[a]alvh.no-ip.org>)
"Porque Kim no hacia nada, pero, eso sí,
con extraordinario éxito" ("Kim", Kipling)
Index: src/backend/access/transam/xlog.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.210
diff -c -r1.210 xlog.c
*** src/backend/access/transam/xlog.c   23 Jul 2005 15:31:16 -0000      1.210
--- src/backend/access/transam/xlog.c   24 Jul 2005 17:55:51 -0000
***************
*** 465,471 ****
                                         TimeLineID endTLI,
                                         uint32 endLogId, uint32 endLogSeg);
  static void WriteControlFile(void);
- static void ReadControlFile(void);
  static char *str_time(time_t tnow);
  static void issue_xlog_fsync(void);
  
--- 465,470 ----
***************
*** 3383,3390 ****
                                 errmsg("could not close control file: %m")));
  }
  
! static void
! ReadControlFile(void)
  {
        pg_crc32        crc;
        int                     fd;
--- 3382,3394 ----
                                 errmsg("could not close control file: %m")));
  }
  
! /*
!  * Read and verify the control file, filling the ControlFile struct.
!  *
!  * If nextXid is not NULL, the latest Checkpoint's nextXid is returned.
!  */
! void
! ReadControlFile(TransactionId *nextXid)
  {
        pg_crc32        crc;
        int                     fd;
***************
*** 3525,3530 ****
--- 3529,3537 ----
                                   ControlFile->lc_ctype),
                 errhint("It looks like you need to initdb or install locale 
support.")));
  
+       if (PointerIsValid(nextXid))
+               *nextXid = ControlFile->checkPointCopy.nextXid;
+ 
        /* Make the fixed locale settings visible as GUC variables, too */
        SetConfigOption("lc_collate", ControlFile->lc_collate,
                                        PGC_INTERNAL, PGC_S_OVERRIDE);
***************
*** 3650,3656 ****
         * for the reasons why).
         */
        if (!IsBootstrapProcessingMode())
!               ReadControlFile();
  }
  
  /*
--- 3657,3663 ----
         * for the reasons why).
         */
        if (!IsBootstrapProcessingMode())
!               ReadControlFile(NULL);
  }
  
  /*
***************
*** 4232,4238 ****
         * Note: in most control paths, *ControlFile is already valid and we 
need
         * not do ReadControlFile() here, but might as well do it to be sure.
         */
!       ReadControlFile();
  
        if (ControlFile->logSeg == 0 ||
                ControlFile->state < DB_SHUTDOWNED ||
--- 4239,4245 ----
         * Note: in most control paths, *ControlFile is already valid and we 
need
         * not do ReadControlFile() here, but might as well do it to be sure.
         */
!       ReadControlFile(NULL);
  
        if (ControlFile->logSeg == 0 ||
                ControlFile->state < DB_SHUTDOWNED ||
Index: src/backend/commands/analyze.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/analyze.c,v
retrieving revision 1.87
diff -c -r1.87 analyze.c
*** src/backend/commands/analyze.c      14 Jul 2005 05:13:39 -0000      1.87
--- src/backend/commands/analyze.c      22 Jul 2005 01:08:51 -0000
***************
*** 317,323 ****
                 * a zero-column table.
                 */
                if (!vacstmt->vacuum)
!                       pgstat_report_analyze(RelationGetRelid(onerel), 0, 0);
  
                vac_close_indexes(nindexes, Irel, AccessShareLock);
                relation_close(onerel, AccessShareLock);
--- 317,324 ----
                 * a zero-column table.
                 */
                if (!vacstmt->vacuum)
!                       pgstat_report_analyze(RelationGetRelid(onerel), 
onerel->rd_rel->relisshared,
!                                                                 0, 0);
  
                vac_close_indexes(nindexes, Irel, AccessShareLock);
                relation_close(onerel, AccessShareLock);
***************
*** 436,443 ****
                }
  
                /* report results to the stats collector, too */
!               pgstat_report_analyze(RelationGetRelid(onerel), totalrows,
!                                                         totaldeadrows);
        }
  
        /* Done with indexes */
--- 437,444 ----
                }
  
                /* report results to the stats collector, too */
!               pgstat_report_analyze(RelationGetRelid(onerel), 
onerel->rd_rel->relisshared,
!                                                         totalrows, 
totaldeadrows);
        }
  
        /* Done with indexes */
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.311
diff -c -r1.311 vacuum.c
*** src/backend/commands/vacuum.c       14 Jul 2005 05:13:39 -0000      1.311
--- src/backend/commands/vacuum.c       24 Jul 2005 15:34:23 -0000
***************
*** 41,46 ****
--- 41,47 ----
  #include "tcop/pquery.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
+ #include "utils/flatfiles.h"
  #include "utils/fmgroids.h"
  #include "utils/inval.h"
  #include "utils/lsyscache.h"
***************
*** 712,718 ****
   *    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.
--- 713,719 ----
   *    vac_update_dbstats() -- update statistics for one database
   *
   *            Update the whole-database statistics that are kept in its 
pg_database
!  *            row, and the flat-file copy of pg_database.
   *
   *            We violate no-overwrite semantics here by storing new values 
for the
   *            statistics columns directly into the tuple that's already on 
the page.
***************
*** 721,728 ****
   *
   *            This routine is shared by full and lazy VACUUM.  Note that it 
is only
   *            applied after a database-wide VACUUM operation.
-  *
-  *            Note that we don't bother to update the flat-file copy of 
pg_database.
   */
  static void
  vac_update_dbstats(Oid dbid,
--- 722,727 ----
***************
*** 768,773 ****
--- 767,775 ----
        heap_endscan(scan);
  
        heap_close(relation, RowExclusiveLock);
+ 
+       /* Mark the flat-file for update at commit */
+       database_file_update_needed();
  }
  
  
***************
*** 1165,1172 ****
                                                vacrelstats->rel_tuples, 
vacrelstats->hasindex);
  
        /* report results to the stats collector, too */
!       pgstat_report_vacuum(RelationGetRelid(onerel), vacstmt->analyze,
!                                                vacrelstats->rel_tuples);
  }
  
  
--- 1167,1174 ----
                                                vacrelstats->rel_tuples, 
vacrelstats->hasindex);
  
        /* report results to the stats collector, too */
!       pgstat_report_vacuum(RelationGetRelid(onerel), 
onerel->rd_rel->relisshared,
!                                                vacstmt->analyze, 
vacrelstats->rel_tuples);
  }
  
  
Index: src/backend/commands/vacuumlazy.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/vacuumlazy.c,v
retrieving revision 1.55
diff -c -r1.55 vacuumlazy.c
*** src/backend/commands/vacuumlazy.c   14 Jul 2005 05:13:40 -0000      1.55
--- src/backend/commands/vacuumlazy.c   22 Jul 2005 01:08:51 -0000
***************
*** 182,189 ****
                                                hasindex);
  
        /* report results to the stats collector, too */
!       pgstat_report_vacuum(RelationGetRelid(onerel), vacstmt->analyze,
!                                                vacrelstats->rel_tuples);
  }
  
  
--- 182,189 ----
                                                hasindex);
  
        /* report results to the stats collector, too */
!       pgstat_report_vacuum(RelationGetRelid(onerel), 
onerel->rd_rel->relisshared,
!                                                vacstmt->analyze, 
vacrelstats->rel_tuples);
  }
  
  
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/libpq/hba.c,v
retrieving revision 1.144
diff -c -r1.144 hba.c
*** src/backend/libpq/hba.c     28 Jun 2005 22:16:45 -0000      1.144
--- src/backend/libpq/hba.c     22 Jul 2005 01:08:51 -0000
***************
*** 39,44 ****
--- 39,45 ----
  
  
  #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
+ #define atoxid(x)  ((TransactionId) strtoul((x), NULL, 10))
  
  /* Max size of username ident server can return */
  #define IDENT_USERNAME_MAX 512
***************
*** 1002,1014 ****
   *    dbname: gets database name (must be of size NAMEDATALEN bytes)
   *    dboid: gets database OID
   *    dbtablespace: gets database's default tablespace's OID
   *
   * This is not much related to the other functions in hba.c, but we put it
   * here because it uses the next_token() infrastructure.
   */
  bool
  read_pg_database_line(FILE *fp, char *dbname,
!                                         Oid *dboid, Oid *dbtablespace)
  {
        char            buf[MAX_TOKEN];
  
--- 1003,1017 ----
   *    dbname: gets database name (must be of size NAMEDATALEN bytes)
   *    dboid: gets database OID
   *    dbtablespace: gets database's default tablespace's OID
+  *    dbfrozenxid: get database's frozen Xid
   *
   * This is not much related to the other functions in hba.c, but we put it
   * here because it uses the next_token() infrastructure.
   */
  bool
  read_pg_database_line(FILE *fp, char *dbname,
!                                         Oid *dboid, Oid *dbtablespace,
!                                         TransactionId *dbfrozenxid)
  {
        char            buf[MAX_TOKEN];
  
***************
*** 1027,1036 ****
        if (!isdigit((unsigned char) buf[0]))
                elog(FATAL, "bad data in flat pg_database file");
        *dbtablespace = atooid(buf);
-       /* discard datfrozenxid */
        next_token(fp, buf, sizeof(buf));
        if (!isdigit((unsigned char) buf[0]))
                elog(FATAL, "bad data in flat pg_database file");
        /* expect EOL next */
        if (next_token(fp, buf, sizeof(buf)))
                elog(FATAL, "bad data in flat pg_database file");
--- 1030,1039 ----
        if (!isdigit((unsigned char) buf[0]))
                elog(FATAL, "bad data in flat pg_database file");
        *dbtablespace = atooid(buf);
        next_token(fp, buf, sizeof(buf));
        if (!isdigit((unsigned char) buf[0]))
                elog(FATAL, "bad data in flat pg_database file");
+       *dbfrozenxid = atoxid(buf);
        /* expect EOL next */
        if (next_token(fp, buf, sizeof(buf)))
                elog(FATAL, "bad data in flat pg_database file");
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.1
diff -c -r1.1 autovacuum.c
*** src/backend/postmaster/autovacuum.c 14 Jul 2005 05:13:40 -0000      1.1
--- src/backend/postmaster/autovacuum.c 24 Jul 2005 17:31:32 -0000
***************
*** 23,29 ****
--- 23,31 ----
  
  #include "access/genam.h"
  #include "access/heapam.h"
+ #include "access/xlog.h"
  #include "catalog/indexing.h"
+ #include "catalog/namespace.h"
  #include "catalog/pg_autovacuum.h"
  #include "catalog/pg_database.h"
  #include "commands/vacuum.h"
***************
*** 41,46 ****
--- 43,49 ----
  #include "tcop/tcopprot.h"
  #include "utils/flatfiles.h"
  #include "utils/fmgroids.h"
+ #include "utils/lsyscache.h"
  #include "utils/memutils.h"
  #include "utils/ps_status.h"
  #include "utils/relcache.h"
***************
*** 68,74 ****
--- 71,79 ----
  {
        Oid                             oid;
        char               *name;
+       TransactionId   frozenxid;
        PgStat_StatDBEntry *entry;
+       int32                   age;
  } autovac_dbase;
  
  
***************
*** 76,83 ****
  static pid_t autovac_forkexec(void);
  #endif
  NON_EXEC_STATIC void AutoVacMain(int argc, char *argv[]);
! static void autovac_check_wraparound(void);
! static void do_autovacuum(PgStat_StatDBEntry *dbentry);
  static List *autovac_get_database_list(void);
  static void test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
                         Form_pg_class classForm, Form_pg_autovacuum avForm,
--- 81,87 ----
  static pid_t autovac_forkexec(void);
  #endif
  NON_EXEC_STATIC void AutoVacMain(int argc, char *argv[]);
! static void do_autovacuum(PgStat_StatDBEntry *dbentry, bool whole_db);
  static List *autovac_get_database_list(void);
  static void test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
                         Form_pg_class classForm, Form_pg_autovacuum avForm,
***************
*** 194,200 ****
--- 198,206 ----
        ListCell           *cell;
        List               *dblist;
        autovac_dbase  *db;
+       bool                    whole_db = false;
        sigjmp_buf              local_sigjmp_buf;
+       TransactionId   nextXid;
  
        /* we are a postmaster subprocess now */
        IsUnderPostmaster = true;
***************
*** 269,289 ****
  
        /*
         * Choose a database to connect to.  We pick the database that was least
!        * recently auto-vacuumed.
         *
         * XXX This could be improved if we had more info about whether it needs
         * vacuuming before connecting to it.  Perhaps look through the pgstats
         * data for the database's tables?
-        *
-        * XXX it is NOT good that we totally ignore databases that have no
-        * pgstats entry ...
         */
        db = NULL;
  
        foreach(cell, dblist)
        {
!               autovac_dbase   *tmp = lfirst(cell);
  
                tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid);
                if (!tmp->entry)
                        continue;
--- 275,327 ----
  
        /*
         * Choose a database to connect to.  We pick the database that was least
!        * recently auto-vacuumed, or one that needs database-wide vacuum (to
!        * prevent Xid wraparound-related data loss.)
         *
         * XXX This could be improved if we had more info about whether it needs
         * vacuuming before connecting to it.  Perhaps look through the pgstats
         * data for the database's tables?
         */
        db = NULL;
  
+       /*
+        * Get the next Xid that was current as of the last checkpoint.
+        * We will use it to determine whether databases are about to need
+        * database-wide vacuums.
+        */
+       ReadControlFile(&nextXid);
+ 
        foreach(cell, dblist)
        {
!               autovac_dbase  *tmp = lfirst(cell);
!               bool                    this_whole_db;
  
+               /*
+                * We decide to vacuum a little earlier than when vacuum.c's
+                * vac_truncate_clog() would decide start giving warnings.  We
+                * look for the database that most urgently needs a 
database-wide
+                * vacuum.  As soon as one is found, any other database is
+                * ignored.
+                */
+               tmp->age = (int32) (nextXid - tmp->frozenxid);
+               this_whole_db = (tmp->age > (int32) ((MaxTransactionId >> 3) * 
3));
+ 
+               if (whole_db || this_whole_db)
+               {
+                       if (!this_whole_db)
+                               continue;
+                       if (!db || tmp->age > db->age)
+                       {
+                               db = tmp;
+                               whole_db = true;
+                       }
+                       continue;
+               }
+ 
+               /*
+                * Skip databases with no pgstat entry; it means it hasn't seen
+                * any activity.
+                */
                tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid);
                if (!tmp->entry)
                        continue;
***************
*** 316,322 ****
                /*
                 * And do an appropriate amount of work on it
                 */
!               do_autovacuum(db->entry);
        }
  
        /* One iteration done, go away */
--- 354,360 ----
                /*
                 * And do an appropriate amount of work on it
                 */
!               do_autovacuum(db->entry, whole_db);
        }
  
        /* One iteration done, go away */
***************
*** 338,343 ****
--- 376,382 ----
        FILE   *db_file;
        Oid             db_id;
        Oid             db_tablespace;
+       TransactionId db_frozenxid;
  
        filename = database_getflatfilename();
        db_file = AllocateFile(filename, "r");
***************
*** 346,352 ****
                                (errcode_for_file_access(),
                                 errmsg("could not open file \"%s\": %m", 
filename)));
  
!       while (read_pg_database_line(db_file, thisname, &db_id, &db_tablespace))
        {
                autovac_dbase   *db;
  
--- 385,392 ----
                                (errcode_for_file_access(),
                                 errmsg("could not open file \"%s\": %m", 
filename)));
  
!       while (read_pg_database_line(db_file, thisname, &db_id, &db_tablespace,
!                                                                &db_frozenxid))
        {
                autovac_dbase   *db;
  
***************
*** 354,359 ****
--- 394,400 ----
  
                db->oid = db_id;
                db->name = pstrdup(thisname);
+               db->frozenxid = db_frozenxid;
                /* this gets set later */
                db->entry = NULL;
  
***************
*** 369,374 ****
--- 410,421 ----
  /*
   * Process a database.
   *
+  * If whole_db is true, the database is processed as a whole, and the
+  * dbentry parameter is ignored.  If it's false, dbentry must hold a valid
+  * pointer to the database entry in the stats databases' hash table, and
+  * it will be used to determine whether vacuum or analyze is needed on a
+  * table per table basis.
+  *
   * Note that test_rel_for_autovac generates two separate lists, one for
   * vacuum and other for analyze.  This is to facilitate processing all
   * analyzes first, and then all vacuums.
***************
*** 377,383 ****
   * order not to ignore shutdown commands for too long.
   */
  static void
! do_autovacuum(PgStat_StatDBEntry *dbentry)
  {
        Relation                classRel,
                                        avRel;
--- 424,430 ----
   * order not to ignore shutdown commands for too long.
   */
  static void
! do_autovacuum(PgStat_StatDBEntry *dbentry, bool whole_db)
  {
        Relation                classRel,
                                        avRel;
***************
*** 387,392 ****
--- 434,441 ----
                                   *analyze_tables = NIL;
        MemoryContext   AutovacMemCxt;
  
+       Assert(dbentry != NULL || whole_db);
+ 
        /* Memory context where cross-transaction state is stored */
        AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
                                                                                
  "Autovacuum context",
***************
*** 405,485 ****
         */
        MemoryContextSwitchTo(AutovacMemCxt);
  
!       /*
!        * If this database is old enough to need a whole-database VACUUM,
!        * don't bother checking each table.  If that happens, this function
!        * will issue the VACUUM command and won't return.
!        */
!       autovac_check_wraparound();
! 
!       CHECK_FOR_INTERRUPTS();
! 
!       classRel = heap_open(RelationRelationId, AccessShareLock);
!       avRel = heap_open(AutovacuumRelationId, AccessShareLock);
! 
!       relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
! 
!       /* Scan pg_class looking for tables to vacuum */
!       while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
        {
!               Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
!               Form_pg_autovacuum avForm = NULL;
!               PgStat_StatTabEntry *tabentry;
!               SysScanDesc     avScan;
!               HeapTuple       avTup;
!               ScanKeyData     entry[1];
!               Oid                     relid;
! 
!               /* Skip non-table entries. */
!               /* XXX possibly allow RELKIND_TOASTVALUE entries here too? */
!               if (classForm->relkind != RELKIND_RELATION)
!                       continue;
!               
!               relid = HeapTupleGetOid(tuple);
! 
!               /* See if we have a pg_autovacuum entry for this relation. */
!               ScanKeyInit(&entry[0],
!                                       Anum_pg_autovacuum_vacrelid,
!                                       BTEqualStrategyNumber, F_OIDEQ,
!                                       ObjectIdGetDatum(relid));
! 
!               avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true,
!                                                                       
SnapshotNow, 1, entry);
! 
!               avTup = systable_getnext(avScan);
! 
!               if (HeapTupleIsValid(avTup))
!                       avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
! 
!               tabentry = hash_search(dbentry->tables, &relid,
!                                                          HASH_FIND, NULL);
  
!               test_rel_for_autovac(relid, tabentry, classForm, avForm,
!                                                        &vacuum_tables, 
&analyze_tables);
  
!               systable_endscan(avScan);
!       }
  
!       heap_endscan(relScan);
!       heap_close(avRel, AccessShareLock);
!       heap_close(classRel, AccessShareLock);
  
!       CHECK_FOR_INTERRUPTS();
  
!       /*
!        * Perform operations on collected tables.
!        */  
  
!       if (analyze_tables)
!               autovacuum_do_vac_analyze(analyze_tables, false);
  
!       CHECK_FOR_INTERRUPTS();
  
!       /* get back to proper context */
!       MemoryContextSwitchTo(AutovacMemCxt);
  
!       if (vacuum_tables)
!               autovacuum_do_vac_analyze(vacuum_tables, true);
  
        /* Finally close out the last transaction. */
        CommitTransactionCommand();
--- 454,548 ----
         */
        MemoryContextSwitchTo(AutovacMemCxt);
  
!       if (whole_db)
        {
!               elog(DEBUG2, "autovacuum: VACUUM ANALYZE whole database");
!               autovacuum_do_vac_analyze(NIL, true);
!       }
!       else
!       {
!               /* Get the stat database entry where pgstat stores shared 
relations */
!               PgStat_StatDBEntry *shared = 
pgstat_fetch_stat_dbentry(InvalidOid);
  
!               CHECK_FOR_INTERRUPTS();
  
!               classRel = heap_open(RelationRelationId, AccessShareLock);
!               avRel = heap_open(AutovacuumRelationId, AccessShareLock);
  
!               relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
! 
!               /* Scan pg_class looking for tables to vacuum */
!               while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != 
NULL)
!               {
!                       Form_pg_class classForm = (Form_pg_class) 
GETSTRUCT(tuple);
!                       Form_pg_autovacuum avForm = NULL;
!                       PgStat_StatTabEntry *tabentry;
!                       SysScanDesc     avScan;
!                       HeapTuple       avTup;
!                       ScanKeyData     entry[1];
!                       Oid                     relid;
!                       Oid                     nspOid;
! 
!                       /* Skip non-table entries. */
!                       /* XXX possibly allow RELKIND_TOASTVALUE entries here 
too? */
!                       if (classForm->relkind != RELKIND_RELATION)
!                               continue;
! 
!                       relid = HeapTupleGetOid(tuple);
! 
!                       /* Skip temp tables (i.e. those in temp namespaces) */
!                       nspOid = get_rel_namespace(relid);
!                       if (isTempNamespace(nspOid))
!                               continue;
! 
!                       /* See if we have a pg_autovacuum entry for this 
relation. */
!                       ScanKeyInit(&entry[0],
!                                               Anum_pg_autovacuum_vacrelid,
!                                               BTEqualStrategyNumber, F_OIDEQ,
!                                               ObjectIdGetDatum(relid));
! 
!                       avScan = systable_beginscan(avRel, 
AutovacuumRelidIndexId, true,
!                                                                               
SnapshotNow, 1, entry);
! 
!                       avTup = systable_getnext(avScan);
! 
!                       if (HeapTupleIsValid(avTup))
!                               avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
! 
!                       if (classForm->relisshared)
!                               tabentry = hash_search(shared->tables, &relid,
!                                                                          
HASH_FIND, NULL);
!                       else
!                               tabentry = hash_search(dbentry->tables, &relid,
!                                                                          
HASH_FIND, NULL);
! 
!                       test_rel_for_autovac(relid, tabentry, classForm, avForm,
!                                                                
&vacuum_tables, &analyze_tables);
! 
!                       systable_endscan(avScan);
!               }
! 
!               heap_endscan(relScan);
!               heap_close(avRel, AccessShareLock);
!               heap_close(classRel, AccessShareLock);
  
!               CHECK_FOR_INTERRUPTS();
  
!               /*
!                * Perform operations on collected tables.
!                */
  
!               if (analyze_tables)
!                       autovacuum_do_vac_analyze(analyze_tables, false);
  
!               CHECK_FOR_INTERRUPTS();
  
!               /* get back to proper context */
!               MemoryContextSwitchTo(AutovacMemCxt);
  
!               if (vacuum_tables)
!                       autovacuum_do_vac_analyze(vacuum_tables, true);
!       }
  
        /* Finally close out the last transaction. */
        CommitTransactionCommand();
***************
*** 607,615 ****
        }
        else if (anltuples > anlthresh)
        {
!               elog(DEBUG2, "will ANALYZE %s",
!                        RelationGetRelationName(rel));
!               *analyze_tables = lappend_oid(*analyze_tables, relid);
        }
  
        RelationClose(rel);
--- 670,682 ----
        }
        else if (anltuples > anlthresh)
        {
!               /* ANALYZE refuses to work with pg_statistics */
!               if (relid != StatisticRelationId)
!               {
!                       elog(DEBUG2, "will ANALYZE %s",
!                                       RelationGetRelationName(rel));
!                       *analyze_tables = lappend_oid(*analyze_tables, relid);
!               }
        }
  
        RelationClose(rel);
***************
*** 646,706 ****
  }
  
  /*
-  * autovac_check_wraparound
-  *            Check database Xid wraparound
-  * 
-  * Check pg_database to see if the last database-wide VACUUM was too long ago,
-  * and issue one now if so.  If this comes to pass, we do not return, as there
-  * is no point in checking individual tables -- they will all get vacuumed
-  * anyway.
-  */
- static void
- autovac_check_wraparound(void)
- {
-       Relation        relation;
-       ScanKeyData     entry[1];
-       HeapScanDesc scan;
-       HeapTuple       tuple;
-       Form_pg_database dbform;
-       int32           age;
-       bool            whole_db;
- 
-       relation = heap_open(DatabaseRelationId, AccessShareLock);
- 
-       /* Must use a heap scan, since there's no syscache for pg_database */
-       ScanKeyInit(&entry[0],
-                               ObjectIdAttributeNumber,
-                               BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(MyDatabaseId));
- 
-       scan = heap_beginscan(relation, SnapshotNow, 1, entry);
- 
-       tuple = heap_getnext(scan, ForwardScanDirection);
- 
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "could not find tuple for database %u", 
MyDatabaseId);
- 
-       dbform = (Form_pg_database) GETSTRUCT(tuple);
- 
-       /*
-        * We decide to vacuum at the same point where vacuum.c's
-        * vac_truncate_clog() would decide to start giving warnings.
-        */
-       age = (int32) (GetTopTransactionId() - dbform->datfrozenxid);
-       whole_db = (age > (int32) ((MaxTransactionId >> 3) * 3));
- 
-       heap_endscan(scan);
-       heap_close(relation, AccessShareLock);
-       
-       if (whole_db)
-       {
-               elog(LOG, "autovacuum: VACUUM ANALYZE whole database");
-               autovacuum_do_vac_analyze(NIL, true);
-               proc_exit(0);
-       }
- }
- 
- /*
   * AutoVacuumingActive
   *            Check GUC vars and report whether the autovacuum process should 
be
   *            running.
--- 713,718 ----
Index: src/backend/postmaster/pgstat.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/postmaster/pgstat.c,v
retrieving revision 1.101
diff -c -r1.101 pgstat.c
*** src/backend/postmaster/pgstat.c     24 Jul 2005 00:33:28 -0000      1.101
--- src/backend/postmaster/pgstat.c     24 Jul 2005 17:55:54 -0000
***************
*** 119,130 ****
  
  static bool pgStatRunningInCollector = FALSE;
  
! static int    pgStatTabstatAlloc = 0;
! static int    pgStatTabstatUsed = 0;
! static PgStat_MsgTabstat **pgStatTabstatMessages = NULL;
  
  #define TABSTAT_QUANTUM               4       /* we alloc this many at a time 
*/
  
  static int    pgStatXactCommit = 0;
  static int    pgStatXactRollback = 0;
  
--- 119,141 ----
  
  static bool pgStatRunningInCollector = FALSE;
  
! /*
!  * Place where backends store per-table info to be sent to the collector.
!  * We store shared relations separately from non-shared ones, to be able to
!  * send them in separate messages.
!  */
! typedef struct TabStatArray
! {
!       int             tsa_alloc;                                      /* num 
allocated */
!       int             tsa_used;                                       /* num 
actually used */
!       PgStat_MsgTabstat **tsa_messages;       /* the array itself */
! } TabStatArray;
  
  #define TABSTAT_QUANTUM               4       /* we alloc this many at a time 
*/
  
+ static TabStatArray RegularTabStat;
+ static TabStatArray SharedTabStat;
+ 
  static int    pgStatXactCommit = 0;
  static int    pgStatXactRollback = 0;
  
***************
*** 182,187 ****
--- 193,199 ----
  static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len);
  static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
  
+ extern void display_statfile_contents(void);
  
  /* ------------------------------------------------------------
   * Public functions called from postmaster follow
***************
*** 614,619 ****
--- 626,632 ----
        if (pgStatSock < 0)
                return;
  
+       /* can't use pgstat_setheader() because it's not called in a backend */
        MemSet(&(msg.m_hdr), 0, sizeof(msg.m_hdr));
        msg.m_hdr.m_type = PGSTAT_MTYPE_BETERM;
        msg.m_hdr.m_procpid = pid;
***************
*** 684,690 ****
   * ---------
   */
  void
! pgstat_report_vacuum(Oid tableoid, bool analyze, PgStat_Counter tuples)
  {
        PgStat_MsgVacuum msg;
  
--- 697,704 ----
   * ---------
   */
  void
! pgstat_report_vacuum(Oid tableoid, bool shared, bool analyze,
!                                        PgStat_Counter tuples)
  {
        PgStat_MsgVacuum msg;
  
***************
*** 692,698 ****
                return;
  
        pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM);
!       msg.m_databaseid = MyDatabaseId;
        msg.m_tableoid = tableoid;
        msg.m_analyze = analyze;
        msg.m_tuples = tuples;
--- 706,715 ----
                return;
  
        pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM);
!       if (shared)
!               msg.m_databaseid = InvalidOid;
!       else
!               msg.m_databaseid = MyDatabaseId;
        msg.m_tableoid = tableoid;
        msg.m_analyze = analyze;
        msg.m_tuples = tuples;
***************
*** 706,712 ****
   * --------
   */
  void
! pgstat_report_analyze(Oid tableoid, PgStat_Counter livetuples,
                                          PgStat_Counter deadtuples)
  {
        PgStat_MsgAnalyze msg;
--- 723,729 ----
   * --------
   */
  void
! pgstat_report_analyze(Oid tableoid, bool shared, PgStat_Counter livetuples,
                                          PgStat_Counter deadtuples)
  {
        PgStat_MsgAnalyze msg;
***************
*** 715,721 ****
                return;
  
        pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE);
!       msg.m_databaseid = MyDatabaseId;
        msg.m_tableoid = tableoid;
        msg.m_live_tuples = livetuples;
        msg.m_dead_tuples = deadtuples;
--- 732,741 ----
                return;
  
        pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE);
!       if (shared)
!               msg.m_databaseid = InvalidOid;
!       else
!               msg.m_databaseid = MyDatabaseId;
        msg.m_tableoid = tableoid;
        msg.m_live_tuples = livetuples;
        msg.m_dead_tuples = deadtuples;
***************
*** 784,790 ****
                  pgstat_collect_blocklevel))
        {
                /* Not reporting stats, so just flush whatever we have */
!               pgStatTabstatUsed = 0;
                return;
        }
  
--- 804,811 ----
                  pgstat_collect_blocklevel))
        {
                /* Not reporting stats, so just flush whatever we have */
!               RegularTabStat.tsa_used = 0;
!               SharedTabStat.tsa_used = 0;
                return;
        }
  
***************
*** 792,800 ****
         * For each message buffer used during the last query set the header
         * fields and send it out.
         */
!       for (i = 0; i < pgStatTabstatUsed; i++)
        {
!               PgStat_MsgTabstat *tsmsg = pgStatTabstatMessages[i];
                int                     n;
                int                     len;
  
--- 813,821 ----
         * For each message buffer used during the last query set the header
         * fields and send it out.
         */
!       for (i = 0; i < RegularTabStat.tsa_used; i++)
        {
!               PgStat_MsgTabstat *tsmsg = RegularTabStat.tsa_messages[i];
                int                     n;
                int                     len;
  
***************
*** 811,818 ****
                tsmsg->m_databaseid = MyDatabaseId;
                pgstat_send(tsmsg, len);
        }
  
!       pgStatTabstatUsed = 0;
  }
  
  
--- 832,857 ----
                tsmsg->m_databaseid = MyDatabaseId;
                pgstat_send(tsmsg, len);
        }
+       RegularTabStat.tsa_used = 0;
+ 
+       /* Ditto, for shared relations */
+       for (i = 0; i < SharedTabStat.tsa_used; i++)
+       {
+               PgStat_MsgTabstat *tsmsg = SharedTabStat.tsa_messages[i];
+               int                     n;
+               int                     len;
  
!               n = tsmsg->m_nentries;
!               len = offsetof(PgStat_MsgTabstat, m_entry[0]) +
!                       n * sizeof(PgStat_TableEntry);
! 
!               /* We don't report transaction commit/abort here */
! 
!               pgstat_setheader(&tsmsg->m_hdr, PGSTAT_MTYPE_TABSTAT);
!               tsmsg->m_databaseid = InvalidOid;
!               pgstat_send(tsmsg, len);
!       }
!       SharedTabStat.tsa_used = 0;
  }
  
  
***************
*** 1045,1081 ****
  }
  
  /*
!  * Create or enlarge the pgStatTabstatMessages array
   */
  static void
! more_tabstat_space(void)
  {
        PgStat_MsgTabstat *newMessages;
        PgStat_MsgTabstat **msgArray;
!       int                     newAlloc = pgStatTabstatAlloc + TABSTAT_QUANTUM;
        int                     i;
  
        /* Create (another) quantum of message buffers */
        newMessages = (PgStat_MsgTabstat *)
                MemoryContextAllocZero(TopMemoryContext,
                                                           
sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);
  
        /* Create or enlarge the pointer array */
!       if (pgStatTabstatMessages == NULL)
                msgArray = (PgStat_MsgTabstat **)
                        MemoryContextAlloc(TopMemoryContext,
                                                           
sizeof(PgStat_MsgTabstat *) * newAlloc);
        else
                msgArray = (PgStat_MsgTabstat **)
!                       repalloc(pgStatTabstatMessages,
                                         sizeof(PgStat_MsgTabstat *) * 
newAlloc);
  
        for (i = 0; i < TABSTAT_QUANTUM; i++)
!               msgArray[pgStatTabstatAlloc + i] = newMessages++;
!       pgStatTabstatMessages = msgArray;
!       pgStatTabstatAlloc = newAlloc;
  
!       Assert(pgStatTabstatUsed < pgStatTabstatAlloc);
  }
  
  /* ----------
--- 1084,1124 ----
  }
  
  /*
!  * Enlarge a TabStatArray
   */
  static void
! more_tabstat_space(TabStatArray *tsarr)
  {
        PgStat_MsgTabstat *newMessages;
        PgStat_MsgTabstat **msgArray;
!       int                     newAlloc;
        int                     i;
  
+       AssertArg(PointerIsValid(tsarr));
+ 
+       newAlloc = tsarr->tsa_alloc + TABSTAT_QUANTUM;
+ 
        /* Create (another) quantum of message buffers */
        newMessages = (PgStat_MsgTabstat *)
                MemoryContextAllocZero(TopMemoryContext,
                                                           
sizeof(PgStat_MsgTabstat) * TABSTAT_QUANTUM);
  
        /* Create or enlarge the pointer array */
!       if (tsarr->tsa_messages == NULL)
                msgArray = (PgStat_MsgTabstat **)
                        MemoryContextAlloc(TopMemoryContext,
                                                           
sizeof(PgStat_MsgTabstat *) * newAlloc);
        else
                msgArray = (PgStat_MsgTabstat **)
!                       repalloc(tsarr->tsa_messages,
                                         sizeof(PgStat_MsgTabstat *) * 
newAlloc);
  
        for (i = 0; i < TABSTAT_QUANTUM; i++)
!               msgArray[tsarr->tsa_alloc + i] = newMessages++;
!       tsarr->tsa_messages = msgArray;
!       tsarr->tsa_alloc = newAlloc;
  
!       Assert(tsarr->tsa_used < tsarr->tsa_alloc);
  }
  
  /* ----------
***************
*** 1092,1097 ****
--- 1135,1141 ----
  {
        Oid                     rel_id = rel->rd_id;
        PgStat_TableEntry *useent;
+       TabStatArray    *tsarr;
        PgStat_MsgTabstat *tsmsg;
        int                     mb;
        int                     i;
***************
*** 1112,1123 ****
                return;
        }
  
        /*
         * Search the already-used message slots for this relation.
         */
!       for (mb = 0; mb < pgStatTabstatUsed; mb++)
        {
!               tsmsg = pgStatTabstatMessages[mb];
  
                for (i = tsmsg->m_nentries; --i >= 0;)
                {
--- 1156,1169 ----
                return;
        }
  
+       tsarr = rel->rd_rel->relisshared ? &SharedTabStat : &RegularTabStat;
+ 
        /*
         * Search the already-used message slots for this relation.
         */
!       for (mb = 0; mb < tsarr->tsa_used; mb++)
        {
!               tsmsg = tsarr->tsa_messages[mb];
  
                for (i = tsmsg->m_nentries; --i >= 0;)
                {
***************
*** 1146,1159 ****
        /*
         * If we ran out of message buffers, we just allocate more.
         */
!       if (pgStatTabstatUsed >= pgStatTabstatAlloc)
!               more_tabstat_space();
  
        /*
         * Use the first entry of the next message buffer.
         */
!       mb = pgStatTabstatUsed++;
!       tsmsg = pgStatTabstatMessages[mb];
        tsmsg->m_nentries = 1;
        useent = &tsmsg->m_entry[0];
        MemSet(useent, 0, sizeof(PgStat_TableEntry));
--- 1192,1205 ----
        /*
         * If we ran out of message buffers, we just allocate more.
         */
!       if (tsarr->tsa_used >= tsarr->tsa_alloc)
!               more_tabstat_space(tsarr);
  
        /*
         * Use the first entry of the next message buffer.
         */
!       mb = tsarr->tsa_used++;
!       tsmsg = tsarr->tsa_messages[mb];
        tsmsg->m_nentries = 1;
        useent = &tsmsg->m_entry[0];
        MemSet(useent, 0, sizeof(PgStat_TableEntry));
***************
*** 1183,1195 ****
         * message buffer used without slots, causing the next report to tell
         * new xact-counters.
         */
!       if (pgStatTabstatAlloc == 0)
!               more_tabstat_space();
  
!       if (pgStatTabstatUsed == 0)
        {
!               pgStatTabstatUsed++;
!               pgStatTabstatMessages[0]->m_nentries = 0;
        }
  }
  
--- 1229,1241 ----
         * message buffer used without slots, causing the next report to tell
         * new xact-counters.
         */
!       if (RegularTabStat.tsa_alloc == 0)
!               more_tabstat_space(&RegularTabStat);
  
!       if (RegularTabStat.tsa_used == 0)
        {
!               RegularTabStat.tsa_used++;
!               RegularTabStat.tsa_messages[0]->m_nentries = 0;
        }
  }
  
***************
*** 1215,1227 ****
         * message buffer used without slots, causing the next report to tell
         * new xact-counters.
         */
!       if (pgStatTabstatAlloc == 0)
!               more_tabstat_space();
  
!       if (pgStatTabstatUsed == 0)
        {
!               pgStatTabstatUsed++;
!               pgStatTabstatMessages[0]->m_nentries = 0;
        }
  }
  
--- 1261,1273 ----
         * message buffer used without slots, causing the next report to tell
         * new xact-counters.
         */
!       if (RegularTabStat.tsa_alloc == 0)
!               more_tabstat_space(&RegularTabStat);
  
!       if (RegularTabStat.tsa_used == 0)
        {
!               RegularTabStat.tsa_used++;
!               RegularTabStat.tsa_messages[0]->m_nentries = 0;
        }
  }
  
***************
*** 2387,2393 ****
   * pgstat_read_statsfile() -
   *
   *    Reads in an existing statistics collector and initializes the
!  *    databases hash table (who's entries point to the tables hash tables)
   *    and the current backend table.
   * ----------
   */
--- 2433,2439 ----
   * pgstat_read_statsfile() -
   *
   *    Reads in an existing statistics collector and initializes the
!  *    databases' hash table (whose entries point to the tables' hash tables)
   *    and the current backend table.
   * ----------
   */
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.460
diff -c -r1.460 postmaster.c
*** src/backend/postmaster/postmaster.c 21 Jul 2005 03:56:11 -0000      1.460
--- src/backend/postmaster/postmaster.c 24 Jul 2005 17:54:31 -0000
***************
*** 1164,1176 ****
                /*
                 * Wait for something to happen.
                 *
!                * We wait at most one minute, to ensure that the other 
background
!                * tasks handled below get done even when no requests are
!                * arriving.
                 */
                memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
  
!               timeout.tv_sec = 60;
                timeout.tv_usec = 0;
  
                PG_SETMASK(&UnBlockSig);
--- 1164,1176 ----
                /*
                 * Wait for something to happen.
                 *
!                * We wait at most one minute, or the minimum autovacuum delay, 
to
!                * ensure that the other background tasks handled below get done
!                * even when no requests are arriving.
                 */
                memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
  
!               timeout.tv_sec = Min(60, autovacuum_naptime);
                timeout.tv_usec = 0;
  
                PG_SETMASK(&UnBlockSig);
Index: src/backend/utils/init/postinit.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/init/postinit.c,v
retrieving revision 1.153
diff -c -r1.153 postinit.c
*** src/backend/utils/init/postinit.c   14 Jul 2005 05:13:41 -0000      1.153
--- src/backend/utils/init/postinit.c   24 Jul 2005 15:50:28 -0000
***************
*** 78,83 ****
--- 78,84 ----
        char       *filename;
        FILE       *db_file;
        char            thisname[NAMEDATALEN];
+       TransactionId frozenxid;
  
        filename = database_getflatfilename();
        db_file = AllocateFile(filename, "r");
***************
*** 86,92 ****
                                (errcode_for_file_access(),
                                 errmsg("could not open file \"%s\": %m", 
filename)));
  
!       while (read_pg_database_line(db_file, thisname, db_id, db_tablespace))
        {
                if (strcmp(thisname, name) == 0)
                {
--- 87,94 ----
                                (errcode_for_file_access(),
                                 errmsg("could not open file \"%s\": %m", 
filename)));
  
!       while (read_pg_database_line(db_file, thisname, db_id, db_tablespace,
!                                                                &frozenxid))
        {
                if (strcmp(thisname, name) == 0)
                {
***************
*** 170,179 ****
        /*
         * Also check that the database is currently allowing connections.
         * (We do not enforce this in standalone mode, however, so that there is
!        * a way to recover from "UPDATE pg_database SET datallowconn = false;")
         */
        dbform = (Form_pg_database) GETSTRUCT(tup);
!       if (IsUnderPostmaster && !dbform->datallowconn)
                ereport(FATAL,
                                
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("database \"%s\" is not currently accepting 
connections",
--- 172,182 ----
        /*
         * Also check that the database is currently allowing connections.
         * (We do not enforce this in standalone mode, however, so that there is
!        * a way to recover from "UPDATE pg_database SET datallowconn = false;".
!        * We do not enforce it for the autovacuum process either.)
         */
        dbform = (Form_pg_database) GETSTRUCT(tup);
!       if (IsUnderPostmaster && !IsAutoVacuumProcess() && 
!dbform->datallowconn)
                ereport(FATAL,
                                
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("database \"%s\" is not currently accepting 
connections",
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.277
diff -c -r1.277 guc.c
*** src/backend/utils/misc/guc.c        23 Jul 2005 21:05:47 -0000      1.277
--- src/backend/utils/misc/guc.c        24 Jul 2005 17:55:56 -0000
***************
*** 1412,1423 ****
        },
  
        {
                {"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
                        gettext_noop("Time to sleep between autovacuum runs, in 
seconds."),
                        NULL
                },
                &autovacuum_naptime,
!               60, 0, INT_MAX, NULL, NULL
        },
        {
                {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
--- 1412,1427 ----
        },
  
        {
+               /*
+                * Note we set an artificial minimum of 1 sec, so that the
+                * postmaster's main loop does not turn into busy-wait.
+                */
                {"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
                        gettext_noop("Time to sleep between autovacuum runs, in 
seconds."),
                        NULL
                },
                &autovacuum_naptime,
!               60, 1, INT_MAX, NULL, NULL
        },
        {
                {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
Index: src/include/pgstat.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/pgstat.h,v
retrieving revision 1.33
diff -c -r1.33 pgstat.h
*** src/include/pgstat.h        14 Jul 2005 05:13:43 -0000      1.33
--- src/include/pgstat.h        22 Jul 2005 01:08:51 -0000
***************
*** 384,393 ****
  extern void pgstat_report_activity(const char *what);
  extern void pgstat_report_tabstat(void);
  extern void pgstat_report_autovac(void);
! extern void pgstat_report_vacuum(Oid tableoid, bool analyze,
                                        PgStat_Counter tuples);
! extern void pgstat_report_analyze(Oid tableoid, PgStat_Counter livetuples,
!                                       PgStat_Counter deadtuples);
  extern int    pgstat_vacuum_tabstat(void);
  
  extern void pgstat_reset_counters(void);
--- 384,393 ----
  extern void pgstat_report_activity(const char *what);
  extern void pgstat_report_tabstat(void);
  extern void pgstat_report_autovac(void);
! extern void pgstat_report_vacuum(Oid tableoid, bool shared, bool analyze,
                                        PgStat_Counter tuples);
! extern void pgstat_report_analyze(Oid tableoid, bool shared,
!                                       PgStat_Counter livetuples, 
PgStat_Counter deadtuples);
  extern int    pgstat_vacuum_tabstat(void);
  
  extern void pgstat_reset_counters(void);
Index: src/include/access/xlog.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/access/xlog.h,v
retrieving revision 1.66
diff -c -r1.66 xlog.h
*** src/include/access/xlog.h   4 Jul 2005 04:51:52 -0000       1.66
--- src/include/access/xlog.h   23 Jul 2005 02:04:33 -0000
***************
*** 155,160 ****
--- 155,161 ----
  extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
  extern void xlog_desc(char *buf, uint8 xl_info, char *rec);
  
+ extern void ReadControlFile(TransactionId *nextXid);
  extern void UpdateControlFile(void);
  extern int    XLOGShmemSize(void);
  extern void XLOGShmemInit(void);
Index: src/include/libpq/hba.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/libpq/hba.h,v
retrieving revision 1.38
diff -c -r1.38 hba.h
*** src/include/libpq/hba.h     28 Jun 2005 05:09:13 -0000      1.38
--- src/include/libpq/hba.h     22 Jul 2005 01:08:51 -0000
***************
*** 37,42 ****
  extern int    hba_getauthmethod(hbaPort *port);
  extern int    authident(hbaPort *port);
  extern bool   read_pg_database_line(FILE *fp, char *dbname,
!                                                                 Oid *dboid, 
Oid *dbtablespace);
  
  #endif /* HBA_H */
--- 37,43 ----
  extern int    hba_getauthmethod(hbaPort *port);
  extern int    authident(hbaPort *port);
  extern bool   read_pg_database_line(FILE *fp, char *dbname,
!                                                                 Oid *dboid, 
Oid *dbtablespace,
!                                                                 TransactionId 
*dbfrozenxid);
  
  #endif /* HBA_H */
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to