Integrate autovacuum functionality into the backend. There's still a
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 14 Jul 2005 05:13:45 +0000 (05:13 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 14 Jul 2005 05:13:45 +0000 (05:13 +0000)
few loose ends to be dealt with, but it seems to work.  Alvaro Herrera,
based on the contrib code by Matthew O'Connor.

25 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/runtime.sgml
src/backend/catalog/Makefile
src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/postmaster/Makefile
src/backend/postmaster/autovacuum.c [new file with mode: 0644]
src/backend/postmaster/pgstat.c
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/init/miscinit.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/catalog/catversion.h
src/include/catalog/indexing.h
src/include/catalog/pg_autovacuum.h [new file with mode: 0644]
src/include/commands/vacuum.h
src/include/pgstat.h
src/include/postmaster/autovacuum.h [new file with mode: 0644]
src/include/tcop/tcopprot.h
src/include/utils/guc_tables.h
src/test/regress/expected/sanity_check.out

index 560a6b3f35f5b2a1d8a6d1d376e36bbe049067f0..fa0abca950c7fb5bbb3d74b46731ada0f9e0c04c 100644 (file)
@@ -1,6 +1,6 @@
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.107 2005/07/07 20:39:56 tgl Exp $
+ $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.108 2005/07/14 05:13:38 tgl Exp $
  -->
 
 <chapter id="catalogs">
       <entry>authorization identifier membership relationships</entry>
      </row>
 
+     <row>
+      <entry><link linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</structname></link></entry>
+      <entry>per-relation autovacuum configuration parameters</entry>
+     </row>
+
      <row>
       <entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
       <entry>casts (data type conversions)</entry>
  </sect1>
 
 
+ <sect1 id="catalog-pg-autovacuum">
+  <title><structname>pg_autovacuum</structname></title>
+
+  <indexterm zone="catalog-pg-autovacuum">
+   <primary>pg_autovacuum</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_autovacuum</structname> stores optional
+   per-relation configuration parameters for <quote>autovacuum</>.
+   If there is an entry here for a particular relation, the given
+   parameters will be used for autovacuuming that table.  If no entry
+   is present, the system-wide defaults will be used.
+  </para>
+
+  <table>
+   <title><structname>pg_autovacuum</> Columns</title>
+
+   <tgroup cols=4>
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Type</entry>
+      <entry>References</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>vacrelid</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
+      <entry>The table this entry is for</entry>
+     </row>
+
+     <row>
+      <entry><structfield>enabled</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>If false, this table is never autovacuumed</entry>
+     </row>
+
+     <row>
+      <entry><structfield>vac_base_thresh</structfield></entry>
+      <entry><type>integer</type></entry>
+      <entry></entry>
+      <entry>Minimum number of modified tuples before vacuum</entry>
+     </row>
+
+     <row>
+      <entry><structfield>vac_scale_factor</structfield></entry>
+      <entry><type>float4</type></entry>
+      <entry></entry>
+      <entry>Multiplier for reltuples to add to
+       <structfield>vac_base_thresh</></entry>
+     </row>
+
+     <row>
+      <entry><structfield>anl_base_thresh</structfield></entry>
+      <entry><type>integer</type></entry>
+      <entry></entry>
+      <entry>Minimum number of modified tuples before analyze</entry>
+     </row>
+
+     <row>
+      <entry><structfield>anl_scale_factor</structfield></entry>
+      <entry><type>float4</type></entry>
+      <entry></entry>
+      <entry>Multiplier for reltuples to add to
+       <structfield>anl_base_thresh</></entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   The autovacuum daemon will initiate a <command>VACUUM</> operation
+   on a particular table when the number of updated or deleted tuples
+   exceeds <structfield>vac_base_thresh</structfield> plus
+   <structfield>vac_scale_factor</structfield> times the number of
+   live tuples currently estimated to be in the relation.
+   Similarly, it will initiate an <command>ANALYZE</> operation
+   when the number of inserted, updated or deleted tuples
+   exceeds <structfield>anl_base_thresh</structfield> plus
+   <structfield>anl_scale_factor</structfield> times the number of
+   live tuples currently estimated to be in the relation.
+  </para>
+
+  <para>
+   Any of the numerical fields can contain <literal>-1</> (or indeed
+   any negative value) to indicate that the system-wide default should
+   be used for this particular value.
+  </para>
+
+ </sect1>
+
+
  <sect1 id="catalog-pg-cast">
   <title><structname>pg_cast</structname></title>
 
index 1aed577b087adbf36ab25e57023d260de3881920..4cae3fa894ccbd27e486b54e5b3b0255d2da4a9d 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.337 2005/07/06 14:45:12 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.338 2005/07/14 05:13:38 tgl Exp $
 -->
 
 <chapter Id="runtime">
@@ -3173,7 +3173,7 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"'  # Windows
         If on, collected statistics are zeroed out whenever the server
         is restarted. If off, statistics are accumulated across server
         restarts. The default is <literal>on</>. This option can only 
-   be set at server start.
+        be set at server start.
        </para>
       </listitem>
      </varlistentry>
@@ -3182,6 +3182,127 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"'  # Windows
     </sect3>
    </sect2>
 
+   <sect2 id="runtime-config-autovacuum">
+    <title>Automatic Vacuuming</title>
+
+     <para>
+      Beginning in <productname>PostgreSQL</> 8.1, there is an optional server
+      process called the <firstterm>autovacuum daemon</>, whose purpose is
+      to automate the issuance of periodic <command>VACUUM</> and
+      <command>ANALYZE</> commands.  When enabled, the autovacuum daemon
+      runs periodically and checks for tables that have had a large number
+      of updated or deleted tuples.  This check uses the row-level statistics
+      collection facility; therefore, the autovacuum daemon cannot be used
+      unless <xref linkend="guc-stats-start-collector"> and
+      <xref linkend="guc-stats-row-level"> are set TRUE.  Also, it's
+      important to allow a slot for the autovacuum process when choosing
+      the value of <xref linkend="guc-superuser-reserved-connections">.
+     </para>
+
+    <variablelist>
+
+     <varlistentry id="guc-autovacuum" xreflabel="autovacuum">
+      <term><varname>autovacuum</varname> (<type>boolean</type>)</term>
+      <indexterm>
+       <primary><varname>autovacuum</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Controls whether the server should start the
+        autovacuum subprocess.  This is off by default.
+        This option can only be set at server start or in the
+        <filename>postgresql.conf</filename> file.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-autovacuum-naptime" xreflabel="autovacuum_naptime">
+      <term><varname>autovacuum_naptime</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>autovacuum_naptime</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies the delay between activity rounds for the autovacuum
+        subprocess.  In each round the subprocess examines one database
+        and issues <command>VACUUM</> and <command>ANALYZE</> commands
+        as needed for tables in that database.  The delay is measured
+        in seconds, and the default is 60.
+        This option can only be set at server start or in the
+        <filename>postgresql.conf</filename> file.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-autovacuum-vacuum-threshold" xreflabel="autovacuum_vacuum_threshold">
+      <term><varname>autovacuum_vacuum_threshold</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>autovacuum_vacuum_threshold</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies the minimum number of updated or deleted tuples needed
+        to trigger a <command>VACUUM</> in any one table.
+        The default is 1000.
+        This option can only be set at server start or in the
+        <filename>postgresql.conf</filename> file.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-autovacuum-analyze-threshold" xreflabel="autovacuum_analyze_threshold">
+      <term><varname>autovacuum_analyze_threshold</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>autovacuum_analyze_threshold</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies the minimum number of inserted, updated or deleted tuples
+        needed to trigger an <command>ANALYZE</> in any one table.
+        The default is 500.
+        This option can only be set at server start or in the
+        <filename>postgresql.conf</filename> file.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-autovacuum-vacuum-scale-factor" xreflabel="autovacuum_vacuum_scale_factor">
+      <term><varname>autovacuum_vacuum_scale_factor</varname> (<type>floating point</type>)</term>
+      <indexterm>
+       <primary><varname>autovacuum_vacuum_scale_factor</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a fraction of the table size to add to
+        <varname>autovacuum_vacuum_threshold</varname>
+        when deciding whether to trigger a <command>VACUUM</>.
+        The default is 0.4.
+        This option can only be set at server start or in the
+        <filename>postgresql.conf</filename> file.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-autovacuum-analyze-scale-factor" xreflabel="autovacuum_analyze_scale_factor">
+      <term><varname>autovacuum_analyze_scale_factor</varname> (<type>floating point</type>)</term>
+      <indexterm>
+       <primary><varname>autovacuum_analyze_scale_factor</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a fraction of the table size to add to
+        <varname>autovacuum_analyze_threshold</varname>
+        when deciding whether to trigger an <command>ANALYZE</>.
+        The default is 0.2.
+        This option can only be set at server start or in the
+        <filename>postgresql.conf</filename> file.
+       </para>
+      </listitem>
+     </varlistentry>
+
+    </variablelist>
+   </sect2>
+
    <sect2 id="runtime-config-client">
     <title>Client Connection Defaults</title>
 
index fdcb2ff5a5942319bef419de1bd42594fd1dd3f5..c2dd227d1d9e9c1357e6c4cac0cc799cdd8e4dd7 100644 (file)
@@ -2,7 +2,7 @@
 #
 # Makefile for backend/catalog
 #
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.55 2005/07/07 20:39:57 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.56 2005/07/14 05:13:39 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -27,7 +27,7 @@ SUBSYS.o: $(OBJS)
 # indexing.h had better be last.
 
 POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
-   pg_proc.h pg_type.h pg_attribute.h pg_class.h \
+   pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
    pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
    pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
    pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
index 9642fa9cf52fc739f20c39f803cabb00a8d3cf26..03783f121e2e92c4a415b51bf0351d23eaaa675c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.86 2005/05/06 17:24:53 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.87 2005/07/14 05:13:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/datum.h"
@@ -77,7 +78,7 @@ static void compute_index_stats(Relation onerel, double totalrows,
                    MemoryContext col_context);
 static VacAttrStats *examine_attribute(Relation onerel, int attnum);
 static int acquire_sample_rows(Relation onerel, HeapTuple *rows,
-                   int targrows, double *totalrows);
+                   int targrows, double *totalrows, double *totaldeadrows);
 static double random_fract(void);
 static double init_selection_state(int n);
 static double get_next_S(double t, int n, double *stateptr);
@@ -108,7 +109,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
    AnlIndexData *indexdata;
    int         targrows,
                numrows;
-   double      totalrows;
+   double      totalrows,
+               totaldeadrows;
    HeapTuple  *rows;
 
    if (vacstmt->verbose)
@@ -309,6 +311,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
     */
    if (attr_cnt <= 0 && !analyzableindex)
    {
+       /*
+        * We report that the table is empty; this is just so that the
+        * autovacuum code doesn't go nuts trying to get stats about
+        * a zero-column table.
+        */
+       if (!vacstmt->vacuum)
+           pgstat_report_analyze(RelationGetRelid(onerel), 0, 0);
+
        vac_close_indexes(nindexes, Irel, AccessShareLock);
        relation_close(onerel, AccessShareLock);
        return;
@@ -340,7 +350,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
     * Acquire the sample rows
     */
    rows = (HeapTuple *) palloc(targrows * sizeof(HeapTuple));
-   numrows = acquire_sample_rows(onerel, rows, targrows, &totalrows);
+   numrows = acquire_sample_rows(onerel, rows, targrows,
+                                 &totalrows, &totaldeadrows);
 
    /*
     * Compute the statistics.  Temporary results during the calculations
@@ -423,6 +434,10 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
                                totalindexrows,
                                false);
        }
+
+       /* report results to the stats collector, too */
+       pgstat_report_analyze(RelationGetRelid(onerel), totalrows,
+                             totaldeadrows);
    }
 
    /* Done with indexes */
@@ -752,23 +767,25 @@ BlockSampler_Next(BlockSampler bs)
  * the number of different blocks represented by the sample tends to be
  * too small.  We can live with that for now.  Improvements are welcome.
  *
- * We also estimate the total number of rows in the table, and return that
- * into *totalrows.  An important property of this sampling method is that
- * because we do look at a statistically unbiased set of blocks, we should
- * get an unbiased estimate of the average number of live rows per block.
- * The previous sampling method put too much credence in the row density near
- * the start of the table.
+ * We also estimate the total numbers of live and dead rows in the table,
+ * and return them into *totalrows and *totaldeadrows, respectively.
+ *
+ * An important property of this sampling method is that because we do
+ * look at a statistically unbiased set of blocks, we should get
+ * unbiased estimates of the average numbers of live and dead rows per
+ * block.  The previous sampling method put too much credence in the row
+ * density near the start of the table.
  *
  * The returned list of tuples is in order by physical position in the table.
  * (We will rely on this later to derive correlation estimates.)
  */
 static int
 acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
-                   double *totalrows)
+                   double *totalrows, double *totaldeadrows)
 {
    int         numrows = 0;    /* # rows collected */
    double      liverows = 0;   /* # rows seen */
-   double      deadrows = 0;
+   double      deadrows = 0;   /* # dead rows seen */
    double      rowstoskip = -1;    /* -1 means not set yet */
    BlockNumber totalblocks;
    BlockSamplerData bs;
@@ -864,11 +881,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
            }
            else
            {
-               /*
-                * Count dead rows, but not empty slots.  This information
-                * is currently not used, but it seems likely we'll want
-                * it someday.
-                */
+               /* Count dead rows, but not empty slots */
                if (targtuple.t_data != NULL)
                    deadrows += 1;
            }
@@ -890,12 +903,18 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
        qsort((void *) rows, numrows, sizeof(HeapTuple), compare_rows);
 
    /*
-    * Estimate total number of live rows in relation.
+    * Estimate total numbers of rows in relation.
     */
    if (bs.m > 0)
+   {
        *totalrows = floor((liverows * totalblocks) / bs.m + 0.5);
+       *totaldeadrows = floor((deadrows * totalblocks) / bs.m + 0.5);
+   }
    else
+   {
        *totalrows = 0.0;
+       *totaldeadrows = 0.0;
+   }
 
    /*
     * Emit some interesting relation info
index f81cdc0daf6ad79c6505e3ea57287b44886cfe7d..23b0911e8cc91cb90f8d5d44072174fa9baa161b 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.310 2005/06/14 22:15:32 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.311 2005/07/14 05:13:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -166,7 +166,8 @@ static TransactionId FreezeLimit;
 
 
 /* non-export function prototypes */
-static List *get_rel_oids(const RangeVar *vacrel, const char *stmttype);
+static List *get_rel_oids(List *relids, const RangeVar *vacrel,
+                         const char *stmttype);
 static void vac_update_dbstats(Oid dbid,
                   TransactionId vacuumXID,
                   TransactionId frozenXID);
@@ -221,9 +222,18 @@ static bool enough_space(VacPage vacpage, Size len);
 
 /*
  * Primary entry point for VACUUM and ANALYZE commands.
+ *
+ * relids is normally NIL; if it is not, then it provides the list of
+ * relation OIDs to be processed, and vacstmt->relation is ignored.
+ * (The non-NIL case is currently only used by autovacuum.)
+ *
+ * It is the caller's responsibility that both vacstmt and relids
+ * (if given) be allocated in a memory context that won't disappear
+ * at transaction commit.  In fact this context must be QueryContext
+ * to avoid complaints from PreventTransactionChain.
  */
 void
-vacuum(VacuumStmt *vacstmt)
+vacuum(VacuumStmt *vacstmt, List *relids)
 {
    const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
    TransactionId initialOldestXmin = InvalidTransactionId;
@@ -302,11 +312,14 @@ vacuum(VacuumStmt *vacstmt)
                                        ALLOCSET_DEFAULT_INITSIZE,
                                        ALLOCSET_DEFAULT_MAXSIZE);
 
-   /* Assume we are processing everything unless one table is mentioned */
-   all_rels = (vacstmt->relation == NULL);
+   /* Remember whether we are processing everything in the DB */
+   all_rels = (relids == NIL && vacstmt->relation == NULL);
 
-   /* Build list of relations to process (note this lives in vac_context) */
-   relations = get_rel_oids(vacstmt->relation, stmttype);
+   /*
+    * Build list of relations to process, unless caller gave us one.
+    * (If we build one, we put it in vac_context for safekeeping.)
+    */
+   relations = get_rel_oids(relids, vacstmt->relation, stmttype);
 
    if (vacstmt->vacuum && all_rels)
    {
@@ -512,11 +525,15 @@ vacuum(VacuumStmt *vacstmt)
  * per-relation transactions.
  */
 static List *
-get_rel_oids(const RangeVar *vacrel, const char *stmttype)
+get_rel_oids(List *relids, const RangeVar *vacrel, const char *stmttype)
 {
    List       *oid_list = NIL;
    MemoryContext oldcontext;
 
+   /* List supplied by VACUUM's caller? */
+   if (relids)
+       return relids;
+
    if (vacrel)
    {
        /* Process a specific relation */
@@ -1146,6 +1163,10 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
    /* update statistics in pg_class */
    vac_update_relstats(RelationGetRelid(onerel), vacrelstats->rel_pages,
                        vacrelstats->rel_tuples, vacrelstats->hasindex);
+
+   /* report results to the stats collector, too */
+   pgstat_report_vacuum(RelationGetRelid(onerel), vacstmt->analyze,
+                        vacrelstats->rel_tuples);
 }
 
 
index 52207000ee3216a7dd076fde9ed928e87d5e7d40..64cab8bbca4f0838a21acbb9dbe721f7ab80e318 100644 (file)
@@ -31,7 +31,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.54 2005/05/19 21:35:46 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.55 2005/07/14 05:13:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,7 @@
 #include "access/xlog.h"
 #include "commands/vacuum.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "storage/freespace.h"
 #include "storage/smgr.h"
 #include "utils/lsyscache.h"
@@ -179,6 +180,10 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
                        vacrelstats->rel_pages,
                        vacrelstats->rel_tuples,
                        hasindex);
+
+   /* report results to the stats collector, too */
+   pgstat_report_vacuum(RelationGetRelid(onerel), vacstmt->analyze,
+                        vacrelstats->rel_tuples);
 }
 
 
index 054bb090609ac4ce9f5fe75aa89b3f97cb8cef55..9eed90863ce43b03e4e45168ff1d9427e547bc99 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for src/backend/postmaster
 #
 # IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.20 2005/03/10 07:14:03 neilc Exp $
+#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.21 2005/07/14 05:13:40 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,8 @@ subdir = src/backend/postmaster
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = bgwriter.o fork_process.o pgarch.o pgstat.o postmaster.o syslogger.o
+OBJS = bgwriter.o autovacuum.o pgarch.o pgstat.o postmaster.o syslogger.o \
+   fork_process.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
new file mode 100644 (file)
index 0000000..de6df77
--- /dev/null
@@ -0,0 +1,750 @@
+/*-------------------------------------------------------------------------
+ *
+ * autovacuum.c
+ *
+ * PostgreSQL Integrated Autovacuum Daemon
+ *
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.1 2005/07/14 05:13:40 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_autovacuum.h"
+#include "catalog/pg_database.h"
+#include "commands/vacuum.h"
+#include "libpq/hba.h"
+#include "libpq/pqsignal.h"
+#include "miscadmin.h"
+#include "pgstat.h"
+#include "postmaster/autovacuum.h"
+#include "postmaster/fork_process.h"
+#include "postmaster/postmaster.h"
+#include "storage/fd.h"
+#include "storage/ipc.h"
+#include "storage/proc.h"
+#include "storage/sinval.h"
+#include "tcop/tcopprot.h"
+#include "utils/flatfiles.h"
+#include "utils/fmgroids.h"
+#include "utils/memutils.h"
+#include "utils/ps_status.h"
+#include "utils/relcache.h"
+
+
+/*
+ * GUC parameters
+ */
+bool       autovacuum_start_daemon = false;
+int            autovacuum_naptime;
+int            autovacuum_vac_thresh;
+double     autovacuum_vac_scale;
+int            autovacuum_anl_thresh;
+double     autovacuum_anl_scale;
+
+/* Flag to tell if we are in the autovacuum daemon process */
+static bool am_autovacuum = false;
+
+/* Last time autovac daemon started/stopped (only valid in postmaster) */
+static time_t last_autovac_start_time = 0;
+static time_t last_autovac_stop_time = 0;
+
+/* struct to keep list of candidate databases for vacuum */
+typedef struct autovac_dbase
+{
+   Oid             oid;
+   char           *name;
+   PgStat_StatDBEntry *entry;
+} autovac_dbase;
+
+
+#ifdef EXEC_BACKEND
+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,
+            List **vacuum_tables, List **analyze_tables);
+static void autovacuum_do_vac_analyze(List *relids, bool dovacuum);
+
+
+/*
+ * Main entry point for autovacuum controller process.
+ *
+ * This code is heavily based on pgarch.c, q.v.
+ */
+int
+autovac_start(void)
+{
+   time_t      curtime;
+   pid_t       AutoVacPID;
+
+   /* Do nothing if no autovacuum process needed */
+   if (!AutoVacuumingActive())
+       return 0;
+
+   /*
+    * Do nothing if too soon since last autovacuum exit.  This limits
+    * how often the daemon runs.  Since the time per iteration can be
+    * quite variable, it seems more useful to measure/control the time
+    * since last subprocess exit than since last subprocess launch.
+    *
+    * However, we *also* check the time since last subprocess launch;
+    * this prevents thrashing under fork-failure conditions.
+    *
+    * Note that since we will be re-called from the postmaster main loop,
+    * we will get another chance later if we do nothing now.
+    *
+    * XXX todo: implement sleep scale factor that existed in contrib code.
+    */
+   curtime = time(NULL);
+   if ((unsigned int) (curtime - last_autovac_stop_time) <
+       (unsigned int) autovacuum_naptime)
+       return 0;
+
+   if ((unsigned int) (curtime - last_autovac_start_time) <
+       (unsigned int) autovacuum_naptime)
+       return 0;
+
+   last_autovac_start_time = curtime;
+
+#ifdef EXEC_BACKEND
+   switch((AutoVacPID = autovac_forkexec()))
+#else
+   switch((AutoVacPID = fork_process()))
+#endif
+   {
+       case -1:
+           ereport(LOG,
+                   (errmsg("could not fork autovacuum process: %m")));
+           return 0;
+
+#ifndef EXEC_BACKEND
+       case 0:
+           /* in postmaster child ... */
+           /* Close the postmaster's sockets */
+           ClosePostmasterPorts(false);
+
+           AutoVacMain(0, NULL);
+           break;
+#endif
+       default:
+           return (int) AutoVacPID;
+   }
+
+   /* shouldn't get here */
+   return 0;
+}
+
+/*
+ * autovac_stopped --- called by postmaster when subprocess exit is detected
+ */
+void
+autovac_stopped(void)
+{
+   last_autovac_stop_time = time(NULL);
+}
+
+#ifdef EXEC_BACKEND
+/*
+ * autovac_forkexec()
+ *
+ * Format up the arglist for the autovacuum process, then fork and exec.
+ */
+static pid_t
+autovac_forkexec(void)
+{
+   char       *av[10];
+   int         ac = 0;
+
+   av[ac++] = "postgres";
+   av[ac++] = "-forkautovac";
+   av[ac++] = NULL;        /* filled in by postmaster_forkexec */
+   av[ac] = NULL;
+
+   Assert(ac < lengthof(av));
+
+   return postmaster_forkexec(ac, av);
+}
+#endif /* EXEC_BACKEND */
+
+/*
+ * AutoVacMain
+ */
+NON_EXEC_STATIC void
+AutoVacMain(int argc, char *argv[])
+{
+   ListCell       *cell;
+   List           *dblist;
+   autovac_dbase  *db;
+   sigjmp_buf      local_sigjmp_buf;
+
+   /* we are a postmaster subprocess now */
+   IsUnderPostmaster = true;
+   am_autovacuum = true;
+
+   /* reset MyProcPid */
+   MyProcPid = getpid();
+
+   /* Lose the postmaster's on-exit routines */
+   on_exit_reset();
+
+   /*
+    * Set up signal handlers.  We operate on databases much like a
+    * regular backend, so we use the same signal handling.  See
+    * equivalent code in tcop/postgres.c.
+    *
+    * Currently, we don't pay attention to postgresql.conf changes
+    * that happen during a single daemon iteration, so we can ignore
+    * SIGHUP.
+    */
+   pqsignal(SIGHUP, SIG_IGN);
+   /*
+    * Presently, SIGINT will lead to autovacuum shutdown, because that's
+    * how we handle ereport(ERROR).  It could be improved however.
+    */
+   pqsignal(SIGINT, StatementCancelHandler);
+   pqsignal(SIGTERM, die);
+   pqsignal(SIGQUIT, quickdie);
+   pqsignal(SIGALRM, handle_sig_alarm);
+
+   pqsignal(SIGPIPE, SIG_IGN);
+   pqsignal(SIGUSR1, CatchupInterruptHandler);
+   /* We don't listen for async notifies */
+   pqsignal(SIGUSR2, SIG_IGN);
+   pqsignal(SIGCHLD, SIG_DFL);
+
+   /* Identify myself via ps */
+   init_ps_display("autovacuum process", "", "");
+   set_ps_display("");
+
+   /* Early initialization */
+   BaseInit();
+
+   /*
+    * If an exception is encountered, processing resumes here.
+    *
+    * See notes in postgres.c about the design of this coding.
+    */
+   if (sigsetjmp(local_sigjmp_buf, 1) != 0)
+   {
+       /* Prevents interrupts while cleaning up */
+       HOLD_INTERRUPTS();
+
+       /* Report the error to the server log */
+       EmitErrorReport();
+
+       /*
+        * We can now go away.  Note that because we'll call InitProcess,
+        * a callback will be registered to do ProcKill, which will clean
+        * up necessary state.
+        */
+       proc_exit(0);
+   }
+
+   /* We can now handle ereport(ERROR) */
+   PG_exception_stack = &local_sigjmp_buf;
+
+   PG_SETMASK(&UnBlockSig);
+
+   /* Get a list of databases */
+   dblist = autovac_get_database_list();
+
+   /*
+    * 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;
+
+       /*
+        * Don't try to access a database that was dropped.  This could only
+        * happen if we read the pg_database flat file right before it was
+        * modified, after the database was dropped from the pg_database
+        * table.
+        */
+       if (tmp->entry->destroy != 0)
+           continue;
+
+       if (!db ||
+           tmp->entry->last_autovac_time < db->entry->last_autovac_time)
+           db = tmp;
+   }
+
+   if (db)
+   {
+       /*
+        * Connect to the selected database
+        */
+       InitPostgres(db->name, NULL);
+       SetProcessingMode(NormalProcessing);
+       pgstat_report_autovac();
+       set_ps_display(db->name);
+       ereport(LOG,
+               (errmsg("autovacuum: processing database \"%s\"", db->name)));
+       /*
+        * And do an appropriate amount of work on it
+        */
+       do_autovacuum(db->entry);
+   }
+
+   /* One iteration done, go away */
+   proc_exit(0);
+}
+
+/*
+ * autovac_get_database_list
+ *
+ *         Return a list of all databases.  Note we cannot use pg_database,
+ *     because we aren't connected yet; we use the flat database file.
+ */
+static List *
+autovac_get_database_list(void)
+{
+   char   *filename;
+   List   *dblist = NIL;
+   char    thisname[NAMEDATALEN];
+   FILE   *db_file;
+   Oid     db_id;
+   Oid     db_tablespace;
+
+   filename = database_getflatfilename();
+   db_file = AllocateFile(filename, "r");
+   if (db_file == NULL)
+       ereport(FATAL,
+               (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;
+
+       db = (autovac_dbase *) palloc(sizeof(autovac_dbase));
+
+       db->oid = db_id;
+       db->name = pstrdup(thisname);
+       /* this gets set later */
+       db->entry = NULL;
+
+       dblist = lappend(dblist, db);
+   }
+
+   FreeFile(db_file);
+   pfree(filename);
+
+   return dblist;
+}
+
+/*
+ * Process a database.
+ *
+ * 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.
+ *
+ * Note that CHECK_FOR_INTERRUPTS is supposed to be used in certain spots in
+ * order not to ignore shutdown commands for too long.
+ */
+static void
+do_autovacuum(PgStat_StatDBEntry *dbentry)
+{
+   Relation        classRel,
+                   avRel;
+   HeapTuple       tuple;
+   HeapScanDesc    relScan;
+   List           *vacuum_tables = NIL,
+                  *analyze_tables = NIL;
+   MemoryContext   AutovacMemCxt;
+
+   /* Memory context where cross-transaction state is stored */
+   AutovacMemCxt = AllocSetContextCreate(TopMemoryContext,
+                                         "Autovacuum context",
+                                         ALLOCSET_DEFAULT_MINSIZE,
+                                         ALLOCSET_DEFAULT_INITSIZE,
+                                         ALLOCSET_DEFAULT_MAXSIZE);
+
+   /* Start a transaction so our commands have one to play into. */
+   StartTransactionCommand();
+
+   /*
+    * StartTransactionCommand and CommitTransactionCommand will
+    * automatically switch to other contexts.  We need this one
+    * to keep the list of relations to vacuum/analyze across
+    * transactions.
+    */
+   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();
+}
+
+/*
+ * test_rel_for_autovac
+ *
+ * Check whether a table needs to be vacuumed or analyzed.  Add it to the
+ * respective list if so.
+ *
+ * A table needs to be vacuumed if the number of dead tuples exceeds a
+ * threshold.  This threshold is calculated as
+ *
+ * threshold = vac_base_thresh + vac_scale_factor * reltuples
+ *
+ * For analyze, the analysis done is that the number of tuples inserted,
+ * deleted and updated since the last analyze exceeds a threshold calculated
+ * in the same fashion as above.  Note that the collector actually stores
+ * the number of tuples (both live and dead) that there were as of the last
+ * analyze.  This is asymmetric to the VACUUM case.
+ *
+ * A table whose pg_autovacuum.enabled value is false, is automatically
+ * skipped.  Thus autovacuum can be disabled for specific tables.
+ *
+ * A table whose vac_base_thresh value is <0 takes the base value from the
+ * autovacuum_vacuum_threshold GUC variable.  Similarly, a vac_scale_factor
+ * value <0 is substituted with the value of
+ * autovacuum_vacuum_scale_factor GUC variable.  Ditto for analyze.
+ */
+static void
+test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
+                    Form_pg_class classForm,
+                    Form_pg_autovacuum avForm,
+                    List **vacuum_tables, List **analyze_tables)
+{
+   Relation        rel;
+   float4          reltuples;  /* pg_class.reltuples */
+   /* constants from pg_autovacuum or GUC variables */
+   int             vac_base_thresh,
+                   anl_base_thresh;
+   float4          vac_scale_factor,
+                   anl_scale_factor;
+   /* thresholds calculated from above constants */
+   float4          vacthresh,
+                   anlthresh;
+   /* number of vacuum (resp. analyze) tuples at this time */
+   float4          vactuples,
+                   anltuples;
+
+   /* User disabled it in pg_autovacuum? */
+   if (avForm && !avForm->enabled)
+       return;
+
+   rel = RelationIdGetRelation(relid);
+   /* The table was recently dropped? */
+   if (rel == NULL)
+       return;
+
+   /* Not found in stat hash? */
+   if (tabentry == NULL)
+   {
+       /*
+        * Analyze this table.  It will emit a stat message for the
+        * collector that will initialize the entry for the next time
+        * around, so we won't have to guess again.
+        */
+       elog(DEBUG2, "table %s not known to stat system, will ANALYZE",
+            RelationGetRelationName(rel));
+       *analyze_tables = lappend_oid(*analyze_tables, relid);
+       RelationClose(rel);
+       return;
+   }
+
+   reltuples = rel->rd_rel->reltuples;
+   vactuples = tabentry->n_dead_tuples;
+   anltuples = tabentry->n_live_tuples + tabentry->n_dead_tuples -
+       tabentry->last_anl_tuples;
+
+   /*
+    * If there is a tuple in pg_autovacuum, use it; else, use the GUC
+    * defaults.  Note that the fields may contain "-1" (or indeed any
+    * negative value), which means use the GUC defaults for each setting.
+    */
+   if (avForm != NULL)
+   {
+       vac_scale_factor = (avForm->vac_scale_factor < 0) ?
+           autovacuum_vac_scale : avForm->vac_scale_factor;
+       vac_base_thresh = (avForm->vac_base_thresh < 0) ?
+           autovacuum_vac_thresh : avForm->vac_base_thresh;
+
+       anl_scale_factor = (avForm->anl_scale_factor < 0) ?
+           autovacuum_anl_scale : avForm->anl_scale_factor;
+       anl_base_thresh = (avForm->anl_base_thresh < 0) ?
+           autovacuum_anl_thresh : avForm->anl_base_thresh;
+   }
+   else
+   {
+       vac_scale_factor = autovacuum_vac_scale;
+       vac_base_thresh = autovacuum_vac_thresh;
+
+       anl_scale_factor = autovacuum_anl_scale;
+       anl_base_thresh = autovacuum_anl_thresh;
+   }
+
+   vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
+   anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
+
+   /*
+    * Note that we don't need to take special consideration for stat
+    * reset, because if that happens, the last vacuum and analyze counts
+    * will be reset too.
+    */
+
+   elog(DEBUG2, "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
+        RelationGetRelationName(rel),
+        vactuples, vacthresh, anltuples, anlthresh);
+
+   /* Determine if this table needs vacuum or analyze. */
+   if (vactuples > vacthresh)
+   {
+       elog(DEBUG2, "will VACUUM ANALYZE %s",
+            RelationGetRelationName(rel));
+       *vacuum_tables = lappend_oid(*vacuum_tables, relid);
+   }
+   else if (anltuples > anlthresh)
+   {
+       elog(DEBUG2, "will ANALYZE %s",
+            RelationGetRelationName(rel));
+       *analyze_tables = lappend_oid(*analyze_tables, relid);
+   }
+
+   RelationClose(rel);
+}
+
+/*
+ * autovacuum_do_vac_analyze
+ *         Vacuum or analyze a list of tables; or all tables if relids = NIL
+ *
+ * We must be in AutovacMemCxt when this routine is called.
+ */
+static void
+autovacuum_do_vac_analyze(List *relids, bool dovacuum)
+{
+   VacuumStmt      *vacstmt = makeNode(VacuumStmt);
+
+   /*
+    * Point QueryContext to the autovac memory context to fake out the
+    * PreventTransactionChain check inside vacuum().  Note that this
+    * is also why we palloc vacstmt instead of just using a local variable.
+    */
+   QueryContext = CurrentMemoryContext;
+
+   /* Set up command parameters */
+   vacstmt->vacuum = dovacuum;
+   vacstmt->full = false;
+   vacstmt->analyze = true;
+   vacstmt->freeze = false;
+   vacstmt->verbose = false;
+   vacstmt->relation = NULL;   /* all tables, or not used if relids != NIL */
+   vacstmt->va_cols = NIL;
+
+   vacuum(vacstmt, relids);
+}
+
+/*
+ * 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.
+ */
+bool
+AutoVacuumingActive(void)
+{
+   if (!autovacuum_start_daemon || !pgstat_collect_startcollector ||
+       !pgstat_collect_tuplelevel)
+       return false;
+   return true;
+}
+
+/*
+ * autovac_init
+ *         This is called at postmaster initialization.
+ *
+ * Annoy the user if he got it wrong.
+ */
+void
+autovac_init(void)
+{
+   if (!autovacuum_start_daemon)
+       return;
+
+   if (!pgstat_collect_startcollector || !pgstat_collect_tuplelevel)
+   {
+       ereport(WARNING,
+               (errmsg("autovacuum not started because of misconfiguration"),
+                errhint("Enable options \"stats_start_collector\" and \"stats_row_level\".")));
+       /*
+        * Set the GUC var so we don't fork autovacuum uselessly, and also to
+        * help debugging.
+        */
+       autovacuum_start_daemon = false;
+   }
+}
+
+/*
+ * IsAutoVacuumProcess
+ *         Return whether this process is an autovacuum process.
+ */
+bool
+IsAutoVacuumProcess(void)
+{
+   return am_autovacuum;
+}
index 325bb8b451ac77c4573189d72c87f15b9973c406..d6096fd2b8fba8ae013eb3cb312a93b39e37d063 100644 (file)
@@ -13,7 +13,7 @@
  *
  * Copyright (c) 2001-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.99 2005/07/04 04:51:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.100 2005/07/14 05:13:40 tgl Exp $
  * ----------
  */
 #include "postgres.h"
@@ -38,6 +38,7 @@
 #include "libpq/pqsignal.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
+#include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
 #include "storage/backendid.h"
@@ -167,7 +168,7 @@ static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
                      int *numbackends);
 static void backend_read_statsfile(void);
 
-static void pgstat_setheader(PgStat_MsgHdr *hdr, int mtype);
+static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
 static void pgstat_send(void *msg, int len);
 
 static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
@@ -177,6 +178,9 @@ static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len);
 static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len);
 static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len);
 static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len);
+static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len);
+static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len);
+static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
 
 
 /* ------------------------------------------------------------
@@ -618,6 +622,27 @@ pgstat_beterm(int pid)
 }
 
 
+/* ----------
+ * pgstat_report_autovac() -
+ *
+ *     Called from autovacuum.c to report startup of an autovacuum process.
+ * ----------
+ */
+void
+pgstat_report_autovac(void)
+{
+   PgStat_MsgAutovacStart msg;
+
+   if (pgStatSock < 0)
+       return;
+
+   pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_AUTOVAC_START);
+   msg.m_databaseid = MyDatabaseId;
+   msg.m_start_time = GetCurrentTimestamp();
+
+   pgstat_send(&msg, sizeof(msg));
+}
+
 /* ------------------------------------------------------------
  * Public functions used by backends follow
  *------------------------------------------------------------
@@ -652,6 +677,51 @@ pgstat_bestart(void)
    on_proc_exit(pgstat_beshutdown_hook, 0);
 }
 
+/* ---------
+ * pgstat_report_vacuum() -
+ *
+ * Tell the collector about the table we just vacuumed.
+ * ---------
+ */
+void
+pgstat_report_vacuum(Oid tableoid, bool analyze, PgStat_Counter tuples)
+{
+   PgStat_MsgVacuum msg;
+
+   if (pgStatSock < 0)
+       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;
+   pgstat_send(&msg, sizeof(msg));
+}
+
+/* --------
+ * pgstat_report_analyze() -
+ *
+ *     Tell the collector about the table we just analyzed.
+ * --------
+ */
+void
+pgstat_report_analyze(Oid tableoid, PgStat_Counter livetuples,
+                     PgStat_Counter deadtuples)
+{
+   PgStat_MsgAnalyze msg;
+
+   if (pgStatSock < 0)
+       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;
+   pgstat_send(&msg, sizeof(msg));
+}
+
 /*
  * Flush any remaining statistics counts out to the collector at process
  * exit.   Without this, operations triggered during backend exit (such as
@@ -1279,7 +1349,7 @@ pgstat_fetch_stat_numbackends(void)
  * ----------
  */
 static void
-pgstat_setheader(PgStat_MsgHdr *hdr, int mtype)
+pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype)
 {
    hdr->m_type = mtype;
    hdr->m_backendid = MyBackendId;
@@ -1653,6 +1723,18 @@ PgstatCollectorMain(int argc, char *argv[])
                                             nread);
                    break;
 
+               case PGSTAT_MTYPE_AUTOVAC_START:
+                   pgstat_recv_autovac((PgStat_MsgAutovacStart *) &msg, nread);
+                   break;
+
+               case PGSTAT_MTYPE_VACUUM:
+                   pgstat_recv_vacuum((PgStat_MsgVacuum *) &msg, nread);
+                   break;
+
+               case PGSTAT_MTYPE_ANALYZE:
+                   pgstat_recv_analyze((PgStat_MsgAnalyze *) &msg, nread);
+                   break;
+
                default:
                    break;
            }
@@ -2049,6 +2131,7 @@ pgstat_get_db_entry(Oid databaseid)
        result->n_blocks_fetched = 0;
        result->n_blocks_hit = 0;
        result->destroy = 0;
+       result->last_autovac_time = 0;
 
        memset(&hash_ctl, 0, sizeof(hash_ctl));
        hash_ctl.keysize = sizeof(Oid);
@@ -2136,6 +2219,7 @@ pgstat_write_statsfile(void)
    PgStat_StatBeDead *deadbe;
    FILE       *fpout;
    int         i;
+   int32       format_id;
 
    /*
     * Open the statistics temp file to write out the current values.
@@ -2150,6 +2234,12 @@ pgstat_write_statsfile(void)
        return;
    }
 
+   /*
+    * Write the file header --- currently just a format ID.
+    */
+   format_id = PGSTAT_FILE_FORMAT_ID;
+   fwrite(&format_id, sizeof(format_id), 1, fpout);
+
    /*
     * Walk through the database table.
     */
@@ -2182,7 +2272,7 @@ pgstat_write_statsfile(void)
        }
 
        /*
-        * Write out the DB line including the number of life backends.
+        * Write out the DB line including the number of live backends.
         */
        fputc('D', fpout);
        fwrite(dbentry, sizeof(PgStat_StatDBEntry), 1, fpout);
@@ -2216,7 +2306,7 @@ pgstat_write_statsfile(void)
            }
 
            /*
-            * At least we think this is still a life table. Print it's
+            * At least we think this is still a live table. Print its
             * access stats.
             */
            fputc('T', fpout);
@@ -2312,6 +2402,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
    HASHCTL     hash_ctl;
    HTAB       *tabhash = NULL;
    FILE       *fpin;
+   int32       format_id;
    int         maxbackends = 0;
    int         havebackends = 0;
    bool        found;
@@ -2319,12 +2410,13 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
    int         mcxt_flags;
 
    /*
-    * If running in the collector we use the DynaHashCxt memory context.
-    * If running in a backend, we use the TopTransactionContext instead,
-    * so the caller must only know the last XactId when this call
-    * happened to know if his tables are still valid or already gone!
+    * If running in the collector or the autovacuum process, we use the
+    * DynaHashCxt memory context.  If running in a backend, we use the
+    * TopTransactionContext instead, so the caller must only know the last
+    * XactId when this call happened to know if his tables are still valid or
+    * already gone!
     */
-   if (pgStatRunningInCollector)
+   if (pgStatRunningInCollector || IsAutoVacuumProcess())
    {
        use_mcxt = NULL;
        mcxt_flags = 0;
@@ -2363,6 +2455,17 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
    if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL)
        return;
 
+   /*
+    * Verify it's of the expected format.
+    */
+   if (fread(&format_id, 1, sizeof(format_id), fpin) != sizeof(format_id)
+       || format_id != PGSTAT_FILE_FORMAT_ID)
+   {
+       ereport(pgStatRunningInCollector ? LOG : WARNING,
+               (errmsg("corrupted pgstat.stat file")));
+       goto done;
+   }
+
    /*
     * We found an existing collector stats file. Read it and put all the
     * hashtable entries into place.
@@ -2552,18 +2655,35 @@ done:
  *
  * Because we store the hash tables in TopTransactionContext, the result
  * is good for the entire current main transaction.
+ *
+ * Inside the autovacuum process, the statfile is assumed to be valid
+ * "forever", that is one iteration, within one database.  This means
+ * we only consider the statistics as they were when the autovacuum
+ * iteration started.
  */
 static void
 backend_read_statsfile(void)
 {
-   TransactionId topXid = GetTopTransactionId();
-
-   if (!TransactionIdEquals(pgStatDBHashXact, topXid))
+   if (IsAutoVacuumProcess())
    {
        Assert(!pgStatRunningInCollector);
-       pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
+       /* already read it? */
+       if (pgStatDBHash)
+           return;
+       pgstat_read_statsfile(&pgStatDBHash, InvalidOid,
                              &pgStatBeTable, &pgStatNumBackends);
-       pgStatDBHashXact = topXid;
+   }
+   else
+   {
+       TransactionId topXid = GetTopTransactionId();
+
+       if (!TransactionIdEquals(pgStatDBHashXact, topXid))
+       {
+           Assert(!pgStatRunningInCollector);
+           pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
+                                 &pgStatBeTable, &pgStatNumBackends);
+           pgStatDBHashXact = topXid;
+       }
    }
 }
 
@@ -2606,6 +2726,129 @@ pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len)
    pgstat_sub_backend(msg->m_hdr.m_procpid);
 }
 
+/* ----------
+ * pgstat_recv_autovac() -
+ *
+ *     Process an autovacuum signalling message.
+ * ----------
+ */
+static void
+pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len)
+{
+   PgStat_StatDBEntry *dbentry;
+
+   /*
+    * Lookup the database in the hashtable.
+    *
+    * XXX this creates the entry if it doesn't exist.  Is this a problem?  (We
+    * could leak an entry if we send an autovac message and the database is
+    * later destroyed, _and_ the messages are rearranged.  Doesn't seem very
+    * likely though.)  Not sure what to do about it.
+    */
+   dbentry = pgstat_get_db_entry(msg->m_databaseid);
+
+   /*
+    * Store the last autovacuum time in the database entry.
+    */
+   dbentry->last_autovac_time = msg->m_start_time;
+}
+
+/* ----------
+ * pgstat_recv_vacuum() -
+ *
+ *     Process a VACUUM message.
+ * ----------
+ */
+static void
+pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
+{
+   PgStat_StatDBEntry *dbentry;
+   PgStat_StatTabEntry *tabentry;
+   bool        found;
+
+   dbentry = pgstat_get_db_entry(msg->m_databaseid);
+
+   tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
+                          HASH_ENTER, &found);
+
+   /*
+    * If we are creating the entry, initialize it.
+    */
+   if (!found)
+   {
+       tabentry->tableid = msg->m_tableoid;
+
+       tabentry->tuples_returned = 0;
+       tabentry->tuples_fetched = 0;
+       tabentry->tuples_inserted = msg->m_tuples;
+       tabentry->tuples_deleted = 0;
+       tabentry->tuples_updated = 0;
+
+       tabentry->n_live_tuples = msg->m_tuples;
+       tabentry->n_dead_tuples = 0;
+
+       if (msg->m_analyze)
+           tabentry->last_anl_tuples = msg->m_tuples;
+       else
+           tabentry->last_anl_tuples = 0;
+
+       tabentry->blocks_fetched = 0;
+       tabentry->blocks_hit = 0;
+   }
+   else
+   {
+       tabentry->n_dead_tuples = 0;
+       tabentry->n_live_tuples = msg->m_tuples;
+       if (msg->m_analyze)
+           tabentry->last_anl_tuples = msg->m_tuples;
+   }
+}
+
+/* ----------
+ * pgstat_recv_analyze() -
+ *
+ *     Process an ANALYZE message.
+ * ----------
+ */
+static void
+pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
+{
+   PgStat_StatDBEntry *dbentry;
+   PgStat_StatTabEntry *tabentry;
+   bool        found;
+
+   dbentry = pgstat_get_db_entry(msg->m_databaseid);
+
+   tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
+                          HASH_ENTER, &found);
+
+   /*
+    * If we are creating the entry, initialize it.
+    */
+   if (!found)
+   {
+       tabentry->tableid = msg->m_tableoid;
+
+       tabentry->tuples_returned = 0;
+       tabentry->tuples_fetched = 0;
+       tabentry->tuples_inserted = 0;
+       tabentry->tuples_deleted = 0;
+       tabentry->tuples_updated = 0;
+
+       tabentry->n_live_tuples = msg->m_live_tuples;
+       tabentry->n_dead_tuples = msg->m_dead_tuples;
+       tabentry->last_anl_tuples = msg->m_live_tuples + msg->m_dead_tuples;
+
+       tabentry->blocks_fetched = 0;
+       tabentry->blocks_hit = 0;
+   }
+   else
+   {
+       tabentry->n_live_tuples = msg->m_live_tuples;
+       tabentry->n_dead_tuples = msg->m_dead_tuples;
+       tabentry->last_anl_tuples = msg->m_live_tuples + msg->m_dead_tuples;
+   }
+}
 
 /* ----------
  * pgstat_recv_activity() -
@@ -2690,6 +2933,10 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
            tabentry->tuples_deleted = tabmsg[i].t_tuples_deleted;
            tabentry->blocks_fetched = tabmsg[i].t_blocks_fetched;
            tabentry->blocks_hit = tabmsg[i].t_blocks_hit;
+           
+           tabentry->n_live_tuples = tabmsg[i].t_tuples_inserted;
+           tabentry->n_dead_tuples = tabmsg[i].t_tuples_updated +
+               tabmsg[i].t_tuples_deleted;
 
            tabentry->destroy = 0;
        }
@@ -2706,6 +2953,10 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
            tabentry->tuples_deleted += tabmsg[i].t_tuples_deleted;
            tabentry->blocks_fetched += tabmsg[i].t_blocks_fetched;
            tabentry->blocks_hit += tabmsg[i].t_blocks_hit;
+
+           tabentry->n_live_tuples += tabmsg[i].t_tuples_inserted;
+           tabentry->n_dead_tuples += tabmsg[i].t_tuples_updated +
+               tabmsg[i].t_tuples_deleted;
        }
 
        /*
index 2de5527648303808ffa23e7334ee285b8bd913e6..6964af6789836dc8a821b0fb05cabff5eb2f8d11 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.458 2005/07/04 04:51:47 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.459 2005/07/14 05:13:40 tgl Exp $
  *
  * NOTES
  *
 #include "miscadmin.h"
 #include "nodes/nodes.h"
 #include "pgstat.h"
+#include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/pgarch.h"
 #include "postmaster/postmaster.h"
@@ -207,6 +208,7 @@ char       *preload_libraries_string = NULL;
 /* PIDs of special child processes; 0 when not running */
 static pid_t StartupPID = 0,
            BgWriterPID = 0,
+           AutoVacPID = 0,
            PgArchPID = 0,
            PgStatPID = 0,
            SysLoggerPID = 0;
@@ -872,8 +874,8 @@ PostmasterMain(int argc, char *argv[])
     *
     * CAUTION: when changing this list, check for side-effects on the signal
     * handling setup of child processes.  See tcop/postgres.c,
-    * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/pgarch.c,
-    * postmaster/pgstat.c, and postmaster/syslogger.c.
+    * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/autovacuum.c,
+    * postmaster/pgarch.c, postmaster/pgstat.c, and postmaster/syslogger.c.
     */
    pqinitmask();
    PG_SETMASK(&BlockSig);
@@ -930,6 +932,11 @@ PostmasterMain(int argc, char *argv[])
     */
    PgStartTime = GetCurrentTimestamp();
 
+   /*
+    * Initialize the autovacuum daemon
+    */
+   autovac_init();
+
    status = ServerLoop();
 
    /*
@@ -1251,6 +1258,15 @@ ServerLoop(void)
                kill(BgWriterPID, SIGUSR2);
        }
 
+       /*
+        * Start a new autovacuum process, if there isn't one running already.
+        * (It'll die relatively quickly.)  We check that it's not started
+        * too frequently in autovac_start.
+        */
+       if (AutoVacuumingActive() && AutoVacPID == 0 &&
+           StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
+           AutoVacPID = autovac_start();
+
        /* If we have lost the archiver, try to start a new one */
        if (XLogArchivingActive() && PgArchPID == 0 &&
            StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
@@ -1818,6 +1834,8 @@ SIGHUP_handler(SIGNAL_ARGS)
        SignalChildren(SIGHUP);
        if (BgWriterPID != 0)
            kill(BgWriterPID, SIGHUP);
+       if (AutoVacPID != 0)
+           kill(AutoVacPID, SIGHUP);
        if (PgArchPID != 0)
            kill(PgArchPID, SIGHUP);
        if (SysLoggerPID != 0)
@@ -1869,6 +1887,16 @@ pmdie(SIGNAL_ARGS)
            ereport(LOG,
                    (errmsg("received smart shutdown request")));
 
+           /*
+            * We won't wait out an autovacuum iteration ...
+            */
+           if (AutoVacPID != 0)
+           {
+               /* Use statement cancel to shut it down */
+               kill(AutoVacPID, SIGINT);
+               break;          /* let reaper() handle this */
+           }
+
            if (DLGetHead(BackendList))
                break;          /* let reaper() handle this */
 
@@ -1905,13 +1933,15 @@ pmdie(SIGNAL_ARGS)
            ereport(LOG,
                    (errmsg("received fast shutdown request")));
 
-           if (DLGetHead(BackendList))
+           if (DLGetHead(BackendList) || AutoVacPID != 0)
            {
                if (!FatalError)
                {
                    ereport(LOG,
                            (errmsg("aborting any active transactions")));
                    SignalChildren(SIGTERM);
+                   if (AutoVacPID != 0)
+                       kill(AutoVacPID, SIGTERM);
                    /* reaper() does the rest */
                }
                break;
@@ -1953,6 +1983,8 @@ pmdie(SIGNAL_ARGS)
                kill(StartupPID, SIGQUIT);
            if (BgWriterPID != 0)
                kill(BgWriterPID, SIGQUIT);
+           if (AutoVacPID != 0)
+               kill(AutoVacPID, SIGQUIT);
            if (PgArchPID != 0)
                kill(PgArchPID, SIGQUIT);
            if (PgStatPID != 0)
@@ -2051,7 +2083,7 @@ reaper(SIGNAL_ARGS)
            /*
             * Go to shutdown mode if a shutdown request was pending.
             * Otherwise, try to start the archiver and stats collector
-            * too.
+            * too.  (We could, but don't, try to start autovacuum here.)
             */
            if (Shutdown > NoShutdown && BgWriterPID != 0)
                kill(BgWriterPID, SIGUSR2);
@@ -2072,8 +2104,8 @@ reaper(SIGNAL_ARGS)
        if (BgWriterPID != 0 && pid == BgWriterPID)
        {
            BgWriterPID = 0;
-           if (exitstatus == 0 && Shutdown > NoShutdown &&
-               !FatalError && !DLGetHead(BackendList))
+           if (exitstatus == 0 && Shutdown > NoShutdown && !FatalError &&
+               !DLGetHead(BackendList) && AutoVacPID == 0)
            {
                /*
                 * Normal postmaster exit is here: we've seen normal exit
@@ -2098,6 +2130,23 @@ reaper(SIGNAL_ARGS)
            continue;
        }
 
+       /*
+        * Was it the autovacuum process?  Normal exit can be ignored;
+        * we'll start a new one at the next iteration of the postmaster's
+        * main loop, if necessary.
+        *
+        * An unexpected exit must crash the system.
+        */
+       if (AutoVacPID != 0 && pid == AutoVacPID)
+       {
+           AutoVacPID = 0;
+           autovac_stopped();
+           if (exitstatus != 0)
+               HandleChildCrash(pid, exitstatus,
+                                _("autovacuum process"));
+           continue;
+       }
+
        /*
         * Was it the archiver?  If so, just try to start a new one; no
         * need to force reset of the rest of the system.  (If fail, we'll
@@ -2156,7 +2205,8 @@ reaper(SIGNAL_ARGS)
         * StartupDataBase.  (We can ignore the archiver and stats
         * processes here since they are not connected to shmem.)
         */
-       if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0)
+       if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0 ||
+           AutoVacPID != 0)
            goto reaper_done;
        ereport(LOG,
            (errmsg("all server processes terminated; reinitializing")));
@@ -2171,7 +2221,7 @@ reaper(SIGNAL_ARGS)
 
    if (Shutdown > NoShutdown)
    {
-       if (DLGetHead(BackendList) || StartupPID != 0)
+       if (DLGetHead(BackendList) || StartupPID != 0 || AutoVacPID != 0)
            goto reaper_done;
        /* Start the bgwriter if not running */
        if (BgWriterPID == 0)
@@ -2239,7 +2289,7 @@ CleanupBackend(int pid,
 }
 
 /*
- * HandleChildCrash -- cleanup after failed backend or bgwriter.
+ * HandleChildCrash -- cleanup after failed backend, bgwriter, or autovacuum.
  *
  * The objectives here are to clean up our local state about the child
  * process, and to signal all other remaining children to quickdie.
@@ -2317,6 +2367,18 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
        kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
    }
 
+   /* Take care of the autovacuum daemon too */
+   if (pid == AutoVacPID)
+       AutoVacPID = 0;
+   else if (AutoVacPID != 0 && !FatalError)
+   {
+       ereport(DEBUG2,
+               (errmsg_internal("sending %s to process %d",
+                                (SendStop ? "SIGSTOP" : "SIGQUIT"),
+                                (int) AutoVacPID)));
+       kill(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
+   }
+
    /* Force a power-cycle of the pgarch process too */
    /* (Shouldn't be necessary, but just for luck) */
    if (PgArchPID != 0 && !FatalError)
@@ -3154,6 +3216,7 @@ SubPostmasterMain(int argc, char *argv[])
     * can attach at the same address the postmaster used.
     */
    if (strcmp(argv[1], "-forkbackend") == 0 ||
+       strcmp(argv[1], "-forkautovac") == 0 ||
        strcmp(argv[1], "-forkboot") == 0)
        PGSharedMemoryReAttach();
 
@@ -3205,6 +3268,17 @@ SubPostmasterMain(int argc, char *argv[])
        BootstrapMain(argc - 2, argv + 2);
        proc_exit(0);
    }
+   if (strcmp(argv[1], "-forkautovac") == 0)
+   {
+       /* Close the postmaster's sockets */
+       ClosePostmasterPorts(false);
+
+       /* Attached process to shared data structures */
+       CreateSharedMemoryAndSemaphores(false, 0);
+
+       AutoVacMain(argc - 2, argv + 2);
+       proc_exit(0);
+   }
    if (strcmp(argv[1], "-forkarch") == 0)
    {
        /* Close the postmaster's sockets */
@@ -3300,7 +3374,11 @@ sigusr1_handler(SIGNAL_ARGS)
         * use of this.
         */
        if (Shutdown <= SmartShutdown)
+       {
            SignalChildren(SIGUSR1);
+           if (AutoVacPID != 0)
+               kill(AutoVacPID, SIGUSR1);
+       }
    }
 
    if (PgArchPID != 0 && Shutdown == NoShutdown)
index 038a482239f0c4a4dad63da2b60b7ee2bcd6bbb7..aab81eabe2bd26ddc7a6ba2cebf7d69419f24bc0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.453 2005/07/10 21:13:58 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.454 2005/07/14 05:13:41 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -2111,7 +2111,7 @@ authdie(SIGNAL_ARGS)
  * Query-cancel signal from postmaster: abort current transaction
  * at soonest convenient time
  */
-static void
+void
 StatementCancelHandler(SIGNAL_ARGS)
 {
    int         save_errno = errno;
index becd2793384b26f8694744587832c8b5885c0c5f..6df4546538da1350cd0f9288d2b6de8dd38dcdc5 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.240 2005/06/30 00:00:51 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.241 2005/07/14 05:13:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -843,7 +843,7 @@ ProcessUtility(Node *parsetree,
            break;
 
        case T_VacuumStmt:
-           vacuum((VacuumStmt *) parsetree);
+           vacuum((VacuumStmt *) parsetree, NIL);
            break;
 
        case T_ExplainStmt:
index ffe7db5f7e517b45da36d5f3bd3547123b0ccd32..389ad06f2fe8a8560ddea4cd2de85fc9a395e525 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.145 2005/07/04 04:51:50 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.146 2005/07/14 05:13:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,6 +32,7 @@
 #include "catalog/pg_authid.h"
 #include "libpq/libpq-be.h"
 #include "miscadmin.h"
+#include "postmaster/autovacuum.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
@@ -394,7 +395,7 @@ void
 InitializeSessionUserIdStandalone(void)
 {
    /* This function should only be called in a single-user backend. */
-   AssertState(!IsUnderPostmaster);
+   AssertState(!IsUnderPostmaster || IsAutoVacuumProcess());
 
    /* call only once */
    AssertState(!OidIsValid(AuthenticatedUserId));
index 18e60cab0f108d4b9be2167ece1c88c7d99e8821..d687c59ec6d989813d9ccd6cdc245458f8415d2d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.152 2005/07/04 04:51:50 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.153 2005/07/14 05:13:41 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -29,6 +29,7 @@
 #include "libpq/hba.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
+#include "postmaster/autovacuum.h"
 #include "postmaster/postmaster.h"
 #include "storage/backendid.h"
 #include "storage/fd.h"
@@ -268,7 +269,8 @@ BaseInit(void)
  * InitPostgres
  *     Initialize POSTGRES.
  *
- * In bootstrap mode neither of the parameters are used.
+ * In bootstrap mode neither of the parameters are used.  In autovacuum
+ * mode, the username parameter is not used.
  *
  * The return value indicates whether the userID is a superuser.  (That
  * can only be tested inside a transaction, so we want to do it during
@@ -282,6 +284,7 @@ bool
 InitPostgres(const char *dbname, const char *username)
 {
    bool        bootstrap = IsBootstrapProcessingMode();
+   bool        autovacuum = IsAutoVacuumProcess();
    bool        am_superuser;
 
    /*
@@ -402,10 +405,11 @@ InitPostgres(const char *dbname, const char *username)
    RelationCacheInitializePhase2();
 
    /*
-    * Figure out our postgres user id.  In standalone mode we use a fixed
-    * id, otherwise we figure it out from the authenticated user name.
+    * Figure out our postgres user id.  In standalone mode and in the
+    * autovacuum process, we use a fixed id, otherwise we figure it out from
+    * the authenticated user name.
     */
-   if (bootstrap)
+   if (bootstrap || autovacuum)
        InitializeSessionUserIdStandalone();
    else if (!IsUnderPostmaster)
    {
@@ -441,7 +445,7 @@ InitPostgres(const char *dbname, const char *username)
    /*
     * Check if user is a superuser.
     */
-   if (bootstrap)
+   if (bootstrap || autovacuum)
        am_superuser = true;
    else
        am_superuser = superuser();
index ca59f6755b4d8f3966acbcdafd1a8583d2d00088..194949fbd733bb0d55011082f2cbfca492dd635f 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.273 2005/07/05 23:18:10 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.274 2005/07/14 05:13:42 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -45,6 +45,7 @@
 #include "optimizer/prep.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "postmaster/autovacuum.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/syslogger.h"
 #include "postmaster/postmaster.h"
@@ -286,6 +287,8 @@ const char *const config_group_names[] =
    gettext_noop("Statistics / Monitoring"),
    /* STATS_COLLECTOR */
    gettext_noop("Statistics / Query and Index Statistics Collector"),
+   /* AUTOVACUUM */
+   gettext_noop("Auto Vacuum"),
    /* CLIENT_CONN */
    gettext_noop("Client Connection Defaults"),
    /* CLIENT_CONN_STATEMENT */
@@ -678,6 +681,15 @@ static struct config_bool ConfigureNamesBool[] =
        false, NULL, NULL
    },
 
+   {
+       {"autovacuum", PGC_SIGHUP, AUTOVACUUM,
+           gettext_noop("Starts the auto vacuum subprocess."),
+           NULL
+       },
+       &autovacuum_start_daemon,
+       false, NULL, NULL    
+   },
+
    {
        {"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS,
            gettext_noop("Generates debugging output for LISTEN and NOTIFY."),
@@ -1389,6 +1401,31 @@ static struct config_int ConfigureNamesInt[] =
        BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL
    },
 
+   {
+       {"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,
+           gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
+           NULL
+       },
+       &autovacuum_vac_thresh,
+       1000, 0, INT_MAX, NULL, NULL
+   },
+   {
+       {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
+           gettext_noop("Minimum number of tuple inserts, updates or deletes prior to analyze."),
+           NULL
+       },
+       &autovacuum_anl_thresh,
+       500, 0, INT_MAX, NULL, NULL
+   },
+
    /* End-of-list marker */
    {
        {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
@@ -1487,6 +1524,23 @@ static struct config_real ConfigureNamesReal[] =
        0.5, 0.0, 1.0, assign_random_seed, show_random_seed
    },
 
+   {
+       {"autovacuum_vacuum_scale_factor", PGC_SIGHUP, AUTOVACUUM,
+           gettext_noop("Number of tuple updates or deletes prior to vacuum as a fraction of reltuples."),
+           NULL
+       },
+       &autovacuum_vac_scale,
+       0.4, 0.0, 100.0, NULL, NULL
+   },
+   {
+       {"autovacuum_analyze_scale_factor", PGC_SIGHUP, AUTOVACUUM,
+           gettext_noop("Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples."),
+           NULL
+       },
+       &autovacuum_anl_scale,
+       0.2, 0.0, 100.0, NULL, NULL
+   },
+
    /* End-of-list marker */
    {
        {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL
index 193b0303b38c070d7cd5224df094431067a579db..dc06658e7f383888bf37917c19586be3480fe33e 100644 (file)
 #stats_reset_on_server_start = on
 
 
+#---------------------------------------------------------------------------
+# AUTOVACUUM PARAMETERS
+#---------------------------------------------------------------------------
+
+#autovacuum = false        # enable autovacuum subprocess?
+#autovacuum_naptime = 60   # time between autovacuum runs, in seconds
+#autovacuum_vacuum_threshold = 1000    # min # of tuple updates before vacuum
+#autovacuum_analyze_threshold = 500    # min # of tuple updates before analyze
+#autovacuum_vacuum_scale_factor = 0.4  # fraction of rel size before vacuum
+#autovacuum_analyze_scale_factor = 0.2 # fraction of rel size before analyze
+
+
 #---------------------------------------------------------------------------
 # CLIENT CONNECTION DEFAULTS
 #---------------------------------------------------------------------------
index 5ce6b4724e12f905e57a4f761f7671a07a4a385d..d87e9f9ce69498d48ee4b39fb2b5dc53943a72cb 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.288 2005/07/10 21:13:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.289 2005/07/14 05:13:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200507102
+#define CATALOG_VERSION_NO 200507131
 
 #endif
index 1ab33708f0cd8a242bfd34d2933bf3028b905ad6..0c4c095e40a47156fce6dadd91a9a4565161f7a7 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.89 2005/07/07 20:39:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.90 2005/07/14 05:13:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -210,6 +210,8 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index,2703, on pg_type using btree(oid oid_ops)
 DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index,2704, on pg_type using btree(typname name_ops, typnamespace oid_ops));
 #define TypeNameNspIndexId  2704
 
+DECLARE_UNIQUE_INDEX(pg_autovacuum_vacrelid_index,1250, on pg_autovacuum using btree(vacrelid oid_ops));
+#define AutovacuumRelidIndexId 1250
 
 /* last step of initialization script: build the indexes declared above */
 BUILD_INDICES
diff --git a/src/include/catalog/pg_autovacuum.h b/src/include/catalog/pg_autovacuum.h
new file mode 100644 (file)
index 0000000..b0bfc20
--- /dev/null
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_autovacuum.h
+ *   definition of the system "autovacuum" relation (pg_autovacuum)
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/pg_autovacuum.h,v 1.1 2005/07/14 05:13:42 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_AUTOVACUUM_H
+#define PG_AUTOVACUUM_H
+
+/* ----------------
+ *     postgres.h contains the system type definitions and the
+ *     CATALOG(), BOOTSTRAP and DATA() sugar words so this file
+ *     can be read by both genbki.sh and the C compiler.
+ * ----------------
+ */
+
+/* ----------------
+ *     pg_autovacuum definition.   cpp turns this into
+ *     typedef struct FormData_pg_autovacuum
+ * ----------------
+ */
+#define AutovacuumRelationId   1248 
+CATALOG(pg_autovacuum,1248) BKI_WITHOUT_OIDS
+{
+   Oid         vacrelid;           /* OID of table */
+   bool        enabled;            /* enabled for this table? */
+   int4        vac_base_thresh;    /* base threshold value */
+   float4      vac_scale_factor;   /* reltuples scaling factor */
+   int4        anl_base_thresh;    /* base threshold value */
+   float4      anl_scale_factor;   /* reltuples scaling factor */
+} FormData_pg_autovacuum;
+
+/* ----------------
+ *     Form_pg_autovacuum corresponds to a pointer to a tuple with
+ *     the format of pg_autovacuum relation.
+ * ----------------
+ */
+typedef FormData_pg_autovacuum *Form_pg_autovacuum;
+
+/* ----------------
+ *     compiler constants for pg_autovacuum
+ * ----------------
+ */
+#define Natts_pg_autovacuum                            6
+#define Anum_pg_autovacuum_vacrelid                    1
+#define Anum_pg_autovacuum_enabled                 2
+#define Anum_pg_autovacuum_vac_base_thresh         3
+#define Anum_pg_autovacuum_vac_scale_factor            4
+#define Anum_pg_autovacuum_anl_base_thresh         5
+#define Anum_pg_autovacuum_anl_scale_factor            6
+
+/* There are no preloaded tuples in pg_autovacuum.h */
+
+#endif   /* PG_AUTOVACUUM_H */
index 0434b6f5ec4b596a1c825ef85e6c85ec255a5b8b..71ec0580229ec865ad0cecf7322593251e00c9cf 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.59 2004/12/31 22:03:28 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.60 2005/07/14 05:13:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -125,7 +125,7 @@ extern DLLIMPORT int default_statistics_target; /* DLLIMPORT for PostGIS */
 
 
 /* in commands/vacuum.c */
-extern void vacuum(VacuumStmt *vacstmt);
+extern void vacuum(VacuumStmt *vacstmt, List *relids);
 extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
                             int *nindexes, Relation **Irel);
 extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode);
index 5612d9129097551b8a4998c817a57004dfdbcbe0..4df12d77d380e444123b5ac4ac298db6ad92deff 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2001-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.32 2005/06/29 22:51:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.33 2005/07/14 05:13:43 tgl Exp $
  * ----------
  */
 #ifndef PGSTAT_H
  * The types of backend/postmaster -> collector messages
  * ----------
  */
-#define PGSTAT_MTYPE_DUMMY         0
-#define PGSTAT_MTYPE_BESTART       1
-#define PGSTAT_MTYPE_BETERM            2
-#define PGSTAT_MTYPE_ACTIVITY      3
-#define PGSTAT_MTYPE_TABSTAT       4
-#define PGSTAT_MTYPE_TABPURGE      5
-#define PGSTAT_MTYPE_DROPDB            6
-#define PGSTAT_MTYPE_RESETCOUNTER  7
+typedef enum StatMsgType
+{
+   PGSTAT_MTYPE_DUMMY,
+   PGSTAT_MTYPE_BESTART,
+   PGSTAT_MTYPE_BETERM,
+   PGSTAT_MTYPE_ACTIVITY,
+   PGSTAT_MTYPE_TABSTAT,
+   PGSTAT_MTYPE_TABPURGE,
+   PGSTAT_MTYPE_DROPDB,
+   PGSTAT_MTYPE_RESETCOUNTER,
+   PGSTAT_MTYPE_AUTOVAC_START,
+   PGSTAT_MTYPE_VACUUM,
+   PGSTAT_MTYPE_ANALYZE
+} StatMsgType;
 
 /* ----------
  * The data type used for counters.
@@ -48,7 +54,7 @@ typedef int64 PgStat_Counter;
  */
 typedef struct PgStat_MsgHdr
 {
-   int         m_type;
+   StatMsgType m_type;
    int         m_size;
    int         m_backendid;
    int         m_procpid;
@@ -114,6 +120,47 @@ typedef struct PgStat_MsgBeterm
    PgStat_MsgHdr m_hdr;
 } PgStat_MsgBeterm;
 
+/* ----------
+ * PgStat_MsgAutovacStart      Sent by the autovacuum daemon to signal
+ *                                 that a database is going to be processed
+ * ----------
+ */
+typedef struct PgStat_MsgAutovacStart
+{
+   PgStat_MsgHdr m_hdr;
+   Oid         m_databaseid;
+   TimestampTz m_start_time;
+} PgStat_MsgAutovacStart;
+
+/* ----------
+ * PgStat_MsgVacuum                Sent by the backend or autovacuum daemon
+ *                                 after VACUUM or VACUUM ANALYZE
+ * ----------
+ */
+typedef struct PgStat_MsgVacuum
+{
+   PgStat_MsgHdr m_hdr;
+   Oid         m_databaseid;
+   Oid         m_tableoid;
+   bool        m_analyze;
+   PgStat_Counter m_tuples;
+} PgStat_MsgVacuum;
+
+/* ----------
+ * PgStat_MsgAnalyze           Sent by the backend or autovacuum daemon
+ *                                 after ANALYZE
+ * ----------
+ */
+typedef struct PgStat_MsgAnalyze
+{
+   PgStat_MsgHdr m_hdr;
+   Oid         m_databaseid;
+   Oid         m_tableoid;
+   PgStat_Counter  m_live_tuples;
+   PgStat_Counter  m_dead_tuples;
+} PgStat_MsgAnalyze;
+
+
 /* ----------
  * PgStat_MsgActivity          Sent by the backends when they start
  *                             to parse a query.
@@ -200,14 +247,22 @@ typedef union PgStat_Msg
    PgStat_MsgTabpurge msg_tabpurge;
    PgStat_MsgDropdb msg_dropdb;
    PgStat_MsgResetcounter msg_resetcounter;
+   PgStat_MsgAutovacStart msg_autovacuum;
+   PgStat_MsgVacuum msg_vacuum;
+   PgStat_MsgAnalyze msg_analyze;
 } PgStat_Msg;
 
 
 /* ------------------------------------------------------------
  * Statistic collector data structures follow
+ *
+ * PGSTAT_FILE_FORMAT_ID should be changed whenever any of these
+ * data structures change.
  * ------------------------------------------------------------
  */
 
+#define PGSTAT_FILE_FORMAT_ID  0x01A5BC93
+
 /* ----------
  * PgStat_StatDBEntry          The collectors data per database
  * ----------
@@ -222,6 +277,7 @@ typedef struct PgStat_StatDBEntry
    PgStat_Counter n_blocks_fetched;
    PgStat_Counter n_blocks_hit;
    int         destroy;
+   TimestampTz last_autovac_time;
 } PgStat_StatDBEntry;
 
 
@@ -282,6 +338,10 @@ typedef struct PgStat_StatTabEntry
    PgStat_Counter tuples_updated;
    PgStat_Counter tuples_deleted;
 
+   PgStat_Counter n_live_tuples;
+   PgStat_Counter n_dead_tuples;
+   PgStat_Counter last_anl_tuples;
+
    PgStat_Counter blocks_fetched;
    PgStat_Counter blocks_hit;
 
@@ -323,6 +383,11 @@ extern void pgstat_bestart(void);
 extern void pgstat_ping(void);
 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);
diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
new file mode 100644 (file)
index 0000000..85667af
--- /dev/null
@@ -0,0 +1,38 @@
+/*-------------------------------------------------------------------------
+ *
+ * autovacuum.h
+ *   header file for integrated autovacuum daemon
+ *
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/postmaster/autovacuum.h,v 1.1 2005/07/14 05:13:43 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef AUTOVACUUM_H
+#define AUTOVACUUM_H
+
+/* GUC variables */
+extern bool        autovacuum_start_daemon; 
+extern int     autovacuum_naptime; 
+extern int     autovacuum_vac_thresh;
+extern double  autovacuum_vac_scale;
+extern int     autovacuum_anl_thresh;
+extern double  autovacuum_anl_scale;
+
+/* Status inquiry functions */
+extern bool AutoVacuumingActive(void);
+extern bool IsAutoVacuumProcess(void);
+
+/* Functions to start autovacuum process, called from postmaster */
+extern void autovac_init(void);
+extern int autovac_start(void);
+extern void autovac_stopped(void);
+
+#ifdef EXEC_BACKEND
+extern void AutoVacMain(int argc, char *argv[]);
+#endif
+
+#endif /* AUTOVACUUM_H */
index d694146d59ae1e69105df913d0dd602f31adc89a..7886d66d7c954f65ef14936210c688c83d1b27dd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.75 2005/06/03 23:05:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.76 2005/07/14 05:13:44 tgl Exp $
  *
  * OLD COMMENTS
  *   This file was created so that other c files could get the two
@@ -58,6 +58,7 @@ extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);
 extern void die(SIGNAL_ARGS);
 extern void quickdie(SIGNAL_ARGS);
 extern void authdie(SIGNAL_ARGS);
+extern void StatementCancelHandler(SIGNAL_ARGS);
 extern void prepare_for_client_read(void);
 extern void client_read_ended(void);
 extern int PostgresMain(int argc, char *argv[], const char *username);
index 39d2af3bab960d95ea7b9ce013c03d40c90b7bf1..beddf5dd5f0a7c21411e4f3c60fde2d52415559a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  *
- *   $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.19 2004/12/31 22:03:46 pgsql Exp $
+ *   $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.20 2005/07/14 05:13:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,6 +62,7 @@ enum config_group
    STATS,
    STATS_MONITORING,
    STATS_COLLECTOR,
+   AUTOVACUUM,
    CLIENT_CONN,
    CLIENT_CONN_STATEMENT,
    CLIENT_CONN_LOCALE,
index 5c0e5ca89511e5d7c857c2d425315328df000437..a6210a1705f112c806fe2ebf2c07d96dc93e7cec 100644 (file)
@@ -40,6 +40,7 @@ SELECT relname, relhasindex
  pg_attribute        | t
  pg_auth_members     | t
  pg_authid           | t
+ pg_autovacuum       | t
  pg_cast             | t
  pg_class            | t
  pg_constraint       | t
@@ -66,7 +67,7 @@ SELECT relname, relhasindex
  shighway            | t
  tenk1               | t
  tenk2               | t
-(56 rows)
+(57 rows)
 
 --
 -- another sanity check: every system catalog that has OIDs should have