]> granicus.if.org Git - postgresql/commitdiff
Remove contrib version of pg_autovacuum --- superseded by integrated
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 29 Jul 2005 19:38:22 +0000 (19:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 29 Jul 2005 19:38:22 +0000 (19:38 +0000)
version.

contrib/Makefile
contrib/README
contrib/pg_autovacuum/Makefile [deleted file]
contrib/pg_autovacuum/README.pg_autovacuum [deleted file]
contrib/pg_autovacuum/TODO [deleted file]
contrib/pg_autovacuum/pg_autovacuum.c [deleted file]
contrib/pg_autovacuum/pg_autovacuum.h [deleted file]

index 971afe6dfeffd1f633a12c12a19e8f63b3fc33f3..cec541490f3ba744445e025a3b80665b9d7f48b0 100644 (file)
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/contrib/Makefile,v 1.59 2005/07/29 15:13:10 momjian Exp $
+# $PostgreSQL: pgsql/contrib/Makefile,v 1.60 2005/07/29 19:38:21 tgl Exp $
 
 subdir = contrib
 top_builddir = ..
@@ -20,7 +20,6 @@ WANTED_DIRS = \
                lo              \
                ltree           \
                oid2name        \
-               pg_autovacuum   \
                pg_buffercache  \
                pg_trgm         \
                pgbench         \
index e1e9a593c7e9266678b434b01d725792a3cb74e6..17e07d7f6ae1cc01bcd58dc270423a86d1dc7fe7 100644 (file)
@@ -102,10 +102,6 @@ oracle -
        Converts Oracle database schema to PostgreSQL
        by Gilles Darold <gilles@darold.net>
 
-pg_autovacuum -
-       Automatically performs vacuum
-       by Matthew T. O'Connor <matthew@zeut.net>
-
 pg_buffercache -
        Real time queries on the shared buffer cache
        by Mark Kirkwood <markir@paradise.net.nz>
@@ -142,7 +138,7 @@ tablefunc -
        Examples of functions returning tables
        by Joe Conway <mail@joeconway.com>
 
-tips/apache_logging -
+tips -
        Getting Apache to log to PostgreSQL
        by Terry Mackintosh <terry@terrym.com>
 
diff --git a/contrib/pg_autovacuum/Makefile b/contrib/pg_autovacuum/Makefile
deleted file mode 100644 (file)
index c512d18..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-PROGRAM = pg_autovacuum
-OBJS   = pg_autovacuum.o dllist.o
-
-PG_CPPFLAGS = -I$(libpq_srcdir) -DFRONTEND
-PG_LIBS = $(libpq_pgport)
-
-DOCS = README.pg_autovacuum
-
-EXTRA_CLEAN = dllist.c
-
-ifdef USE_PGXS
-PGXS = $(shell pg_config --pgxs)
-include $(PGXS)
-else
-subdir = contrib/pg_autovacuum
-top_builddir = ../..
-include $(top_builddir)/src/Makefile.global
-include $(top_srcdir)/contrib/contrib-global.mk
-endif
-
-dllist.c: $(top_srcdir)/src/backend/lib/dllist.c
-       rm -f $@ && $(LN_S) $< .
diff --git a/contrib/pg_autovacuum/README.pg_autovacuum b/contrib/pg_autovacuum/README.pg_autovacuum
deleted file mode 100644 (file)
index f208421..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-pg_autovacuum README
---------------------
-
-pg_autovacuum is a libpq client program that monitors all the
-databases associated with a PostgreSQL server.  It uses the statistics
-collector to monitor insert, update and delete activity.  
-
-When a table exceeds a insert or delete threshold (for more detail on
-thresholds, see "Vacuum and Analyze" below) then that table will be
-vacuumed and/or analyzed.
-
-This allows PostgreSQL to keep the FSM (Free Space Map) and table
-statistics up to date, and eliminates the need to schedule periodic
-vacuums.
-
-The primary benefit of pg_autovacuum is that the FSM and table
-statistic information are updated more nearly as frequently as needed.
-When a table is actively changing, pg_autovacuum will perform the
-VACUUMs and ANALYZEs that such a table needs, whereas if a table
-remains static, no cycles will be wasted performing this
-unnecessarily.
-
-A secondary benefit of pg_autovacuum is that it ensures that a
-database wide vacuum is performed prior to XID wraparound.  This is an
-important, if rare, problem, as failing to do so can result in major
-data loss.  (See the section in the _Administrator's Guide_ entitled
-"Preventing transaction ID wraparound failures" for more details.)
-
-KNOWN ISSUES:
--------------
-
-pg_autovacuum has been tested under Redhat Linux (by me) and Debian
-GNU/Linux, Solaris, and AIX (by Christopher B. Browne) and all known
-bugs have been resolved.  Please report any problems to the hackers
-list.
-
-pg_autovacuum requires that the statistics system be enabled and
-reporting row level stats.  The overhead of the stats system has been
-shown to be significant under certain workloads.  For instance, a
-tight loop of queries performing "select 1" was found to run nearly
-30% slower when row-level stats were enabled.  However, in practice,
-with more realistic workloads, the stats system overhead is usually
-nominal.
-
-pg_autovacuum does not get started automatically by either the
-postmaster or by pg_ctl.  Similarly, when the postmaster exits, no one
-tells pg_autovacuum.  The result of that is that at the start of the
-next loop, pg_autovacuum will fail to connect to the server and
-exit().  Any time it fails to connect pg_autovacuum exit()s.
-
-While pg_autovacuum can manage vacuums for as many databases as you
-may have tied to a particular PostgreSQL postmaster, it can only
-connect to a single PostgreSQL postmaster.  Thus, if you have multiple
-postmasters on a particular host, you will need multiple pg_autovacuum
-instances, and they have no way, at present, to coordinate between one
-another to ensure that they do not concurrently vacuum big tables.
-
-When installed as a service under Windows, there is currently no way to
-know the name of the PostgreSQL server service (if there even is one)
-so it is not possible to specify a startup dependency. It is therefore
-possible for pg_autovacuum to start before the server.
-
-When installed as a service under Windows, if the -P option is used to
-specify the connection password, this option (and the password) is 
-stored in plain text in the registry.
-
-TODO:
------
-
-At present, there are no sample scripts to automatically start up
-pg_autovacuum along with the database.  It would be desirable to have
-a SysV script to start up pg_autovacuum after PostgreSQL has been
-started.
-
-Some users have expressed interest in making pg_autovacuum more
-configurable so that certain tables known to be inactive could be
-excluded from being vacuumed.  It would probably make sense to
-introduce this sort of functionality by providing arguments to specify
-the database and schema in which to find a configuration table.
-
-It would also be desirable for the daemon to monitor how busy the
-system is, with a view to deferring vacuums until there is less other
-activity.
-
-INSTALL:
---------
-
-As of postgresql v7.4 pg_autovacuum is included in the main source
-tree under contrib.  Therefore you merely need to "make && make
-install" (similar to most other contrib modules) and it will be
-installed for you.
-
-If you are using an earlier version of PostgreSQL, uncompress the
-tar.gz file into the contrib directory and modify the contrib/Makefile
-to include the pg_autovacuum directory.  pg_autovacuum will then be
-built as part of the standard postgresql install.  It is known to work
-with v7.3 releases; it is not presently compatible with v7.2.
-
-make sure that the following are set in postgresql.conf:
-
-  stats_start_collector = true
-  stats_row_level = true
-
-Start up the postmaster, then execute the pg_autovacuum executable.
-
-If you have a script that automatically starts up the PostgreSQL
-instance, you might add in, after that, something similar to the
-following:
-
-  sleep 10    # To give the database some time to start up
-  $PGBINS/pg_autovacuum -D -s $SBASE -S $SSCALE ... [other arguments]
-
-Command line arguments:
------------------------
-
-pg_autovacuum has the following optional arguments:
-
--d debug: 0 silent, 1 basic info, 2 more debug info,  etc...
--D daemonize: Detach from tty and run in background.
--s sleep base value: see "Sleeping" below.
--S sleep scaling factor: see "Sleeping" below.
--v vacuum base threshold: see "Vacuum and Analyze" below.
--V vacuum scaling factor: see "Vacuum and Analyze" below.
--a analyze base threshold: see "Vacuum and Analyze" below.
--A analyze scaling factor: see "Vacuum and Analyze" below.
--i update interval: how often (in terms of iterations of the primary loop
-   over the database list) to update the database list. The default is 2,
-   which means the list will be updated before every other pass through
-   the database list.
--L log file: Name of file to which output is submitted, otherwise STDERR
--U username: Username pg_autovacuum will use to connect with, if not
-   specified the current username is used.
--P password: Password pg_autovacuum will use to connect with. *WARNING*
-   This option is insecure. When installed as a Windows Service, this
-   option will be stored in plain text in the registry. When used with
-   most Unix variants, other users will be able to see the argument to
-   the "-P" option via ps(1). The ~/.pgpass file can be used to
-   specify a password more securely.
--H host: host name or IP to connect to.
--p port: port used for connection.
--h help: list of command line options.
-
-The following 5 autovacuum command line options correspond to the various
-cost-based vacuum settings.  If not given, then the cluster default values
-will be used.
-
--c     vacuum_cost_delay
--C     vacuum_cost_page_hit
--m     vacuum_cost_page_miss
--n     vacuum_cost_page_dirty
--l     vacuum_cost_limit
-
-
-Numerous arguments have default values defined in pg_autovacuum.h.  At
-the time of writing they are:
-
--d 1
--v 1000
--V 2   
--a 500 (half of -v if not specified)
--A 1   (half of -V if not specified)
--s 300 (5 minutes)
--S 2
--i 2
-
-The following arguments are used on Windows only:
-
--I Install the executable as a Windows service. Other appropriate command
-   line options will be stored in the registry and passed to the service 
-   at startup. *WARNING* This includes the connection password which will 
-   be stored in plain text.
-            
--N service user: Name of the Windows user account under which the service
-   will run. Only used when installing as a Windows service.
-   
--W service password: The password for the service account. Only used when 
-   installing as a Windows service.
-
--R Uninstall pg_autovacuum as a service.
-
--E Dependent service that must start before this service. Normally this will be
-   a PostgreSQL instance, e.g. "-E pgsql-8.0.0". Only used when installing as 
-   a Windows service.
-
-Vacuum and Analyze:
--------------------
-
-pg_autovacuum performs either a VACUUM ANALYZE or just ANALYZE
-depending on the mixture of table activity (insert, update, or
-delete):
-
-- If the number of (inserts + updates + deletes) > AnalyzeThreshold, then
-  only an analyze is performed.
-
-- If the number of (deletes + updates) > VacuumThreshold, then a
-  vacuum analyze is performed.
-
-VacuumThreshold is equal to:
-    vacuum_base_value + (vacuum_scaling_factor * "number of tuples in the table")
-
-AnalyzeThreshold is equal to:
-    analyze_base_value + (analyze_scaling_factor * "number of tuples in the table")
-
-The AnalyzeThreshold defaults to half of the VacuumThreshold since it
-represents a much less expensive operation (approx 5%-10% of vacuum),
-and running ANALYZE more often should not substantially degrade system
-performance.
-
-Sleeping:
----------
-
-pg_autovacuum sleeps for a while after it is done checking all the
-databases.  It does this in order to limit the amount of system
-resources it consumes.  This allows the system administrator to
-configure pg_autovacuum to be more or less aggressive.
-
-Reducing the sleep time will cause pg_autovacuum to respond more
-quickly to changes, whether they be database addition/removal, table
-addition/removal, or just normal table activity.
-
-On the other hand, setting pg_autovacuum to sleep values too
-aggressively (to too short periods of time) can have a negative effect
-on server performance.  For instance, if a table gets vacuumed 5 times
-during the course of a large set of updates, this is likely to take a
-lot more work than if the table was vacuumed just once, at the end.
-
-The total time it sleeps is equal to:
-
-  base_sleep_value + sleep_scaling_factor * "duration of the previous
-  loop"
-
-Note that timing measurements are made in seconds; specifying
-"pg_vacuum -s 1" means pg_autovacuum could poll the database up to 60
-times minute.  In a system with large tables where vacuums may run for
-several minutes, rather longer times between vacuums are likely to be
-appropriate.
-
-What pg_autovacuum monitors:
-----------------------------
-
-pg_autovacuum dynamically generates a list of all databases and tables
-that exist on the server.  It will dynamically add and remove
-databases and tables that are removed from the database server while
-pg_autovacuum is running.  Overhead is fairly small per object.  For
-example: 10 databases with 10 tables each appears to less than 10k of
-memory on my Linux box.
diff --git a/contrib/pg_autovacuum/TODO b/contrib/pg_autovacuum/TODO
deleted file mode 100644 (file)
index b93f2e2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-Todo Items for pg_autovacuum client
---------------------------------------------------------------------------
-
-_Add Startup Message (with datetime stamp) to Logfile when starting and logging 
-
-_create a FSM export function and see if I can use it for pg_autovacuum
-
-_look into possible benifits of pgstattuple contrib work
-
-_Continue trying to reduce server load created by polling.
-
-Done:
---------------------------------------------------------------------------
-_Check if required pg_stats are enables, if not exit with error
-
-_Reduce the number connections and queries to the server
-       _Make database adding and removal part of the normal loop
-       _make table adding and removal part of the normal loop
-
-_Separate logic for vacuum and analyze
-
-_all pg_autovacuum specific functions are now static
-
-_correct usage of snprintf
-
-_reworked database and table update functions, now they
-       use the existing database connection and only one query
-
-_fixed -h option output
-
-_cleanup of 'constant == variable' used much more consistently now.
-
-_Guarantee database wide vacuum prior to Xid wraparound
-
-_change name to pg_autovacuum
-
-_Add proper table and database removal functions so that we can properly
-       clear up before we exit, and make sure we don't leak memory when removing tables and such.
-
-_Decouple insert and delete thresholds
-
-_Fix Vacuum debug routine to include the database name.
-
-_Allow it to detach from the tty
-
diff --git a/contrib/pg_autovacuum/pg_autovacuum.c b/contrib/pg_autovacuum/pg_autovacuum.c
deleted file mode 100644 (file)
index 36b10d6..0000000
+++ /dev/null
@@ -1,1862 +0,0 @@
-/* pg_autovacuum.c
- * All the code for the pg_autovacuum program
- * (c) 2003 Matthew T. O'Connor
- * Revisions by Christopher B. Browne, Liberty RMS
- * Win32 Service code added by Dave Page
- *
- * $PostgreSQL: pgsql/contrib/pg_autovacuum/pg_autovacuum.c,v 1.35 2005/06/15 13:55:23 momjian Exp $
- */
-
-#include "postgres_fe.h"
-
-#include <unistd.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-#include <time.h>
-#include <sys/time.h>
-#ifdef WIN32
-#include <windows.h>
-#endif
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "pg_autovacuum.h"
-
-#ifdef WIN32
-SERVICE_STATUS ServiceStatus;
-SERVICE_STATUS_HANDLE hStatus;
-int                    appMode = 0;
-char       deps[255];
-#endif
-
-/* define atooid */
-#define atooid(x)  ((Oid) strtoul((x), NULL, 10))
-
-
-static cmd_args *args;
-static FILE       *LOGOUTPUT;
-static char            logbuffer[4096];
-
-
-/* The main program loop function */
-static int     VacuumLoop(int argc, char **argv);
-
-/* Functions for dealing with command line arguements */
-static cmd_args *get_cmd_args(int argc, char *argv[]);
-static void print_cmd_args(void);
-static void free_cmd_args(void);
-static void usage(void);
-
-/* Functions for managing database lists */
-static Dllist *init_db_list(void);
-static db_info *init_dbinfo(char *dbname, Oid oid, long age);
-static void update_db_list(Dllist *db_list);
-static void remove_db_from_list(Dlelem *db_to_remove);
-static void print_db_info(db_info * dbi, int print_table_list);
-static void print_db_list(Dllist *db_list, int print_table_lists);
-static int     xid_wraparound_check(db_info * dbi);
-static void free_db_list(Dllist *db_list);
-
-/* Functions for managing table lists */
-static tbl_info *init_table_info(PGresult *conn, int row, db_info * dbi);
-static void update_table_list(db_info * dbi);
-static void remove_table_from_list(Dlelem *tbl_to_remove);
-static void print_table_list(Dllist *tbl_node);
-static void print_table_info(tbl_info * tbl);
-static void update_table_thresholds(db_info * dbi, tbl_info * tbl, int vacuum_type);
-static void free_tbl_list(Dllist *tbl_list);
-
-/* A few database helper functions */
-static int     check_stats_enabled(db_info * dbi);
-static PGconn *db_connect(db_info * dbi);
-static void db_disconnect(db_info * dbi);
-static PGresult *send_query(const char *query, db_info * dbi);
-
-/* Other Generally needed Functions */
-#ifndef WIN32
-static void daemonize(void);
-#endif
-static void log_entry(const char *logentry, int level);
-
-#ifdef WIN32
-/* Windows Service related functions */
-static void ControlHandler(DWORD request);
-static int     InstallService();
-static int     RemoveService();
-#endif
-
-
-static void
-log_entry(const char *logentry, int level)
-{
-       /*
-        * Note: Under Windows we dump the log entries to the normal
-        * stderr/logfile as well, otherwise it can be a pain to debug
-        * service install failures etc.
-        */
-
-       time_t          curtime;
-       struct tm  *loctime;
-       char            timebuffer[128],
-                               slevel[10];
-
-
-#ifdef WIN32
-       static HANDLE evtHandle = INVALID_HANDLE_VALUE;
-       static int      last_level;
-       WORD            elevel;
-#endif
-
-       switch (level)
-       {
-               case LVL_DEBUG:
-                       sprintf(slevel, "DEBUG:   ");
-                       break;
-
-               case LVL_INFO:
-                       sprintf(slevel, "INFO:    ");
-                       break;
-
-               case LVL_WARNING:
-                       sprintf(slevel, "WARNING: ");
-                       break;
-
-               case LVL_ERROR:
-                       sprintf(slevel, "ERROR:   ");
-                       break;
-
-               case LVL_EXTRA:
-                       sprintf(slevel, "         ");
-                       break;
-
-               default:
-                       sprintf(slevel, "         ");
-                       break;
-       }
-
-       curtime = time(NULL);
-       loctime = localtime(&curtime);
-       strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S %Z", loctime);
-       fprintf(LOGOUTPUT, "[%s] %s%s\n", timebuffer, slevel, logentry);
-
-#ifdef WIN32
-
-       /* Restore the previous level if this is extra info */
-       if (level == LVL_EXTRA)
-               level = last_level;
-       last_level = level;
-
-       switch (level)
-       {
-               case LVL_DEBUG:
-                       elevel = EVENTLOG_INFORMATION_TYPE;
-                       break;
-
-               case LVL_INFO:
-                       elevel = EVENTLOG_SUCCESS;
-                       break;
-
-               case LVL_WARNING:
-                       elevel = EVENTLOG_WARNING_TYPE;
-                       break;
-
-               case LVL_ERROR:
-                       elevel = EVENTLOG_ERROR_TYPE;
-                       break;
-
-               default:
-                       elevel = EVENTLOG_SUCCESS;
-                       break;
-       }
-
-       if (evtHandle == INVALID_HANDLE_VALUE)
-       {
-               evtHandle = RegisterEventSource(NULL, "PostgreSQL Auto Vacuum");
-               if (evtHandle == NULL)
-               {
-                       evtHandle = INVALID_HANDLE_VALUE;
-                       return;
-               }
-       }
-
-       ReportEvent(evtHandle, elevel, 0, 0, NULL, 1, 0, &logentry, NULL);
-#endif
-}
-
-/*
- * Function used to detach the pg_autovacuum daemon from the tty and go into
- * the background.
- *
- * This code is ripped directly from pmdaemonize in postmaster.c.
- */
-#ifndef WIN32
-static void
-daemonize(void)
-{
-       int                     i;
-       pid_t           pid;
-
-       pid = fork();
-       if (pid == (pid_t) -1)
-       {
-               log_entry("cannot disassociate from controlling TTY", LVL_ERROR);
-               fflush(LOGOUTPUT);
-               _exit(1);
-       }
-       else if (pid)
-       {                                                       /* parent */
-               /* Parent should just exit, without doing any atexit cleanup */
-               _exit(0);
-       }
-
-/* GH: If there's no setsid(), we hopefully don't need silent mode.
- * Until there's a better solution.
- */
-#ifdef HAVE_SETSID
-       if (setsid() < 0)
-       {
-               log_entry("cannot disassociate from controlling TTY", LVL_ERROR);
-               fflush(LOGOUTPUT);
-               _exit(1);
-       }
-#endif
-       i = open(NULL_DEV, O_RDWR);
-       dup2(i, 0);
-       dup2(i, 1);
-       dup2(i, 2);
-       close(i);
-}
-#endif   /* WIN32 */
-
-/* Create and return tbl_info struct with initialized to values from row or res */
-static tbl_info *
-init_table_info(PGresult *res, int row, db_info * dbi)
-{
-       tbl_info   *new_tbl = (tbl_info *) malloc(sizeof(tbl_info));
-
-       if (!new_tbl)
-       {
-               log_entry("init_table_info: Cannot get memory", LVL_ERROR);
-               fflush(LOGOUTPUT);
-               return NULL;
-       }
-
-       if (res == NULL)
-               return NULL;
-
-       new_tbl->dbi = dbi;                     /* set pointer to db */
-
-       new_tbl->schema_name = (char *)
-               malloc(strlen(PQgetvalue(res, row, PQfnumber(res, "schemaname"))) + 1);
-       if (!new_tbl->schema_name)
-       {
-               log_entry("init_table_info: malloc failed on new_tbl->schema_name", LVL_ERROR);
-               fflush(LOGOUTPUT);
-               return NULL;
-       }
-       strcpy(new_tbl->schema_name,
-                  PQgetvalue(res, row, PQfnumber(res, "schemaname")));
-
-       new_tbl->table_name = (char *)
-               malloc(strlen(PQgetvalue(res, row, PQfnumber(res, "relname"))) +
-                          strlen(new_tbl->schema_name) + 6);
-       if (!new_tbl->table_name)
-       {
-               log_entry("init_table_info: malloc failed on new_tbl->table_name", LVL_ERROR);
-               fflush(LOGOUTPUT);
-               return NULL;
-       }
-
-       /*
-        * Put both the schema and table name in quotes so that we can work
-        * with mixed case table names
-        */
-       strcpy(new_tbl->table_name, "\"");
-       strcat(new_tbl->table_name, new_tbl->schema_name);
-       strcat(new_tbl->table_name, "\".\"");
-       strcat(new_tbl->table_name, PQgetvalue(res, row, PQfnumber(res, "relname")));
-       strcat(new_tbl->table_name, "\"");
-
-       new_tbl->CountAtLastAnalyze =
-               (atol(PQgetvalue(res, row, PQfnumber(res, "n_tup_ins"))) +
-                atol(PQgetvalue(res, row, PQfnumber(res, "n_tup_upd"))) +
-                atol(PQgetvalue(res, row, PQfnumber(res, "n_tup_del"))));
-       new_tbl->curr_analyze_count = new_tbl->CountAtLastAnalyze;
-
-       new_tbl->CountAtLastVacuum =
-               (atol(PQgetvalue(res, row, PQfnumber(res, "n_tup_del"))) +
-                atol(PQgetvalue(res, row, PQfnumber(res, "n_tup_upd"))));
-       new_tbl->curr_vacuum_count = new_tbl->CountAtLastVacuum;
-
-       new_tbl->relid = atooid(PQgetvalue(res, row, PQfnumber(res, "oid")));
-       new_tbl->reltuples = atof(PQgetvalue(res, row, PQfnumber(res, "reltuples")));
-       new_tbl->relpages = atooid(PQgetvalue(res, row, PQfnumber(res, "relpages")));
-
-       if (strcmp("t", PQgetvalue(res, row, PQfnumber(res, "relisshared"))))
-               new_tbl->relisshared = 0;
-       else
-               new_tbl->relisshared = 1;
-
-       new_tbl->analyze_threshold =
-               args->analyze_base_threshold + args->analyze_scaling_factor * new_tbl->reltuples;
-       new_tbl->vacuum_threshold =
-               args->vacuum_base_threshold + args->vacuum_scaling_factor * new_tbl->reltuples;
-
-       if (args->debug >= 2)
-               print_table_info(new_tbl);
-
-       return new_tbl;
-}
-
-/* Set thresholds = base_value + scaling_factor * reltuples
-   Should be called after a vacuum since vacuum updates values in pg_class */
-static void
-update_table_thresholds(db_info * dbi, tbl_info * tbl, int vacuum_type)
-{
-       PGresult   *res = NULL;
-       int                     disconnect = 0;
-       char            query[128];
-
-       if (dbi->conn == NULL)
-       {
-               dbi->conn = db_connect(dbi);
-               disconnect = 1;
-       }
-
-       if (dbi->conn != NULL)
-       {
-               snprintf(query, sizeof(query), PAGES_QUERY, tbl->relid);
-               res = send_query(query, dbi);
-               if (res != NULL)
-               {
-                       tbl->reltuples =
-                               atof(PQgetvalue(res, 0, PQfnumber(res, "reltuples")));
-                       tbl->relpages = atooid(PQgetvalue(res, 0, PQfnumber(res, "relpages")));
-
-                       /*
-                        * update vacuum thresholds only of we just did a vacuum
-                        * analyze
-                        */
-                       if (vacuum_type == VACUUM_ANALYZE)
-                       {
-                               tbl->vacuum_threshold =
-                                       (args->vacuum_base_threshold + args->vacuum_scaling_factor * tbl->reltuples);
-                               tbl->CountAtLastVacuum = tbl->curr_vacuum_count;
-                       }
-
-                       /* update analyze thresholds */
-                       tbl->analyze_threshold =
-                               (args->analyze_base_threshold + args->analyze_scaling_factor * tbl->reltuples);
-                       tbl->CountAtLastAnalyze = tbl->curr_analyze_count;
-
-                       PQclear(res);
-
-                       /*
-                        * If the stats collector is reporting fewer updates then we
-                        * have on record then the stats were probably reset, so we
-                        * need to reset also
-                        */
-                       if ((tbl->curr_analyze_count < tbl->CountAtLastAnalyze) ||
-                               (tbl->curr_vacuum_count < tbl->CountAtLastVacuum))
-                       {
-                               tbl->CountAtLastAnalyze = tbl->curr_analyze_count;
-                               tbl->CountAtLastVacuum = tbl->curr_vacuum_count;
-                       }
-               }
-       }
-       if (disconnect)
-               db_disconnect(dbi);
-}
-
-static void
-update_table_list(db_info * dbi)
-{
-       int                     disconnect = 0;
-       PGresult   *res = NULL;
-       tbl_info   *tbl = NULL;
-       Dlelem     *tbl_elem = DLGetHead(dbi->table_list);
-       int                     i = 0,
-                               t = 0,
-                               found_match = 0;
-
-       if (dbi->conn == NULL)
-       {
-               dbi->conn = db_connect(dbi);
-               disconnect = 1;
-       }
-
-       if (dbi->conn != NULL)
-       {
-               /*
-                * Get a result set that has all the information we will need to
-                * both remove tables from the list that no longer exist and add
-                * tables to the list that are new
-                */
-               res = send_query((char *) TABLE_STATS_QUERY, dbi);
-               if (res != NULL)
-               {
-                       t = PQntuples(res);
-
-                       /*
-                        * First: use the tbl_list as the outer loop and the result
-                        * set as the inner loop, this will determine what tables
-                        * should be removed
-                        */
-                       while (tbl_elem != NULL)
-                       {
-                               tbl = ((tbl_info *) DLE_VAL(tbl_elem));
-                               found_match = 0;
-
-                               for (i = 0; i < t; i++)
-                               {                               /* loop through result set looking for a
-                                                                * match */
-                                       if (tbl->relid == atooid(PQgetvalue(res, i, PQfnumber(res, "oid"))))
-                                       {
-                                               found_match = 1;
-                                               break;
-                                       }
-                               }
-                               if (found_match == 0)
-                               {                               /* then we didn't find this tbl_elem in
-                                                                * the result set */
-                                       Dlelem     *elem_to_remove = tbl_elem;
-
-                                       tbl_elem = DLGetSucc(tbl_elem);
-                                       remove_table_from_list(elem_to_remove);
-                               }
-                               else
-                                       tbl_elem = DLGetSucc(tbl_elem);
-                       }                                       /* Done removing dropped tables from the
-                                                                * table_list */
-
-                       /*
-                        * Then loop use result set as outer loop and tbl_list as the
-                        * inner loop to determine what tables are new
-                        */
-                       for (i = 0; i < t; i++)
-                       {
-                               tbl_elem = DLGetHead(dbi->table_list);
-                               found_match = 0;
-                               while (tbl_elem != NULL)
-                               {
-                                       tbl = ((tbl_info *) DLE_VAL(tbl_elem));
-                                       if (tbl->relid == atooid(PQgetvalue(res, i, PQfnumber(res, "oid"))))
-                                       {
-                                               found_match = 1;
-                                               break;
-                                       }
-                                       tbl_elem = DLGetSucc(tbl_elem);
-                               }
-                               if (found_match == 0)   /* then we didn't find this result
-                                                                                * now in the tbl_list */
-                               {
-                                       DLAddTail(dbi->table_list, DLNewElem(init_table_info(res, i, dbi)));
-                                       if (args->debug >= 1)
-                                       {
-                                               sprintf(logbuffer, "added table: %s.%s", dbi->dbname,
-                                                               ((tbl_info *) DLE_VAL(DLGetTail(dbi->table_list)))->table_name);
-                                               log_entry(logbuffer, LVL_DEBUG);
-                                       }
-                               }
-                       }                                       /* end of for loop that adds tables */
-               }
-               fflush(LOGOUTPUT);
-               PQclear(res);
-               res = NULL;
-               if (args->debug >= 3)
-                       print_table_list(dbi->table_list);
-               if (disconnect)
-                       db_disconnect(dbi);
-       }
-}
-
-/* Free memory, and remove the node from the list */
-static void
-remove_table_from_list(Dlelem *tbl_to_remove)
-{
-       tbl_info   *tbl = ((tbl_info *) DLE_VAL(tbl_to_remove));
-
-       if (args->debug >= 1)
-       {
-               sprintf(logbuffer, "Removing table: %s.%s from list.", tbl->dbi->dbname, tbl->table_name);
-               log_entry(logbuffer, LVL_DEBUG);
-               fflush(LOGOUTPUT);
-       }
-       DLRemove(tbl_to_remove);
-
-       if (tbl->schema_name)
-       {
-               free(tbl->schema_name);
-               tbl->schema_name = NULL;
-       }
-       if (tbl->table_name)
-       {
-               free(tbl->table_name);
-               tbl->table_name = NULL;
-       }
-       if (tbl)
-       {
-               free(tbl);
-               tbl = NULL;
-       }
-       DLFreeElem(tbl_to_remove);
-}
-
-/* Free the entire table list */
-static void
-free_tbl_list(Dllist *tbl_list)
-{
-       Dlelem     *tbl_elem = DLGetHead(tbl_list);
-       Dlelem     *tbl_elem_to_remove = NULL;
-
-       while (tbl_elem != NULL)
-       {
-               tbl_elem_to_remove = tbl_elem;
-               tbl_elem = DLGetSucc(tbl_elem);
-               remove_table_from_list(tbl_elem_to_remove);
-       }
-       DLFreeList(tbl_list);
-}
-
-static void
-print_table_list(Dllist *table_list)
-{
-       Dlelem     *table_elem = DLGetHead(table_list);
-
-       while (table_elem != NULL)
-       {
-               print_table_info(((tbl_info *) DLE_VAL(table_elem)));
-               table_elem = DLGetSucc(table_elem);
-       }
-}
-
-static void
-print_table_info(tbl_info * tbl)
-{
-       sprintf(logbuffer, "  table name: %s.%s", tbl->dbi->dbname, tbl->table_name);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "     relid: %u;   relisshared: %d", tbl->relid, tbl->relisshared);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "     reltuples: %f;  relpages: %u", tbl->reltuples, tbl->relpages);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "     curr_analyze_count: %li; curr_vacuum_count: %li",
-                       tbl->curr_analyze_count, tbl->curr_vacuum_count);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "     last_analyze_count: %li; last_vacuum_count: %li",
-                       tbl->CountAtLastAnalyze, tbl->CountAtLastVacuum);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "     analyze_threshold: %li; vacuum_threshold: %li",
-                       tbl->analyze_threshold, tbl->vacuum_threshold);
-       log_entry(logbuffer, LVL_INFO);
-       fflush(LOGOUTPUT);
-}
-
-/* End of table Management Functions */
-
-/* Beginning of DB Management Functions */
-
-/* init_db_list() creates the db_list and initalizes template1 */
-static Dllist *
-init_db_list(void)
-{
-       Dllist     *db_list = DLNewList();
-       db_info    *dbs = NULL;
-       PGresult   *res = NULL;
-#ifdef WIN32
-       int                     k = 0;
-#endif
-
-       DLAddHead(db_list, DLNewElem(init_dbinfo((char *) "template1", 0, 0)));
-       if (DLGetHead(db_list) == NULL)
-       {                                                       /* Make sure init_dbinfo was successful */
-               log_entry("init_db_list(): Error creating db_list for db: template1.", LVL_ERROR);
-               fflush(LOGOUTPUT);
-               return NULL;
-       }
-
-       /*
-        * We do this just so we can set the proper oid for the template1
-        * database
-        */
-       dbs = ((db_info *) DLE_VAL(DLGetHead(db_list)));
-       dbs->conn = db_connect(dbs);
-
-#ifdef WIN32
-       while (dbs->conn == NULL && !appMode && k < 10)
-       {
-               int        j;
-
-               /* Pause for 30 seconds to allow the database to start up */
-               log_entry("Pausing 30 seconds to allow the database to startup completely", LVL_INFO);
-               fflush(LOGOUTPUT);
-               ServiceStatus.dwWaitHint = 10;
-               for (j=0; j<6; j++)
-               {
-                       pg_usleep(5000000);
-                       ServiceStatus.dwCheckPoint++;
-                       SetServiceStatus(hStatus, &ServiceStatus);
-                       fflush(LOGOUTPUT);
-               }
-
-               /* now try again */
-               log_entry("Attempting to connect again.", LVL_INFO);
-               dbs->conn = db_connect(dbs);
-               k++;
-       }
-#endif
-
-       if (dbs->conn != NULL)
-       {
-               res = send_query(FROZENOID_QUERY, dbs);
-               if (res != NULL)
-               {
-                       dbs->oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
-                       dbs->age = atol(PQgetvalue(res, 0, PQfnumber(res, "age")));
-                       if (res)
-                               PQclear(res);
-
-                       if (args->debug >= 2)
-                               print_db_list(db_list, 0);
-               }
-               else
-                       return NULL;
-       }
-       return db_list;
-}
-
-/* Simple function to create an instance of the dbinfo struct
-       Initalizes all the pointers and connects to the database  */
-static db_info *
-init_dbinfo(char *dbname, Oid oid, long age)
-{
-       db_info    *newdbinfo = (db_info *) malloc(sizeof(db_info));
-
-       newdbinfo->analyze_threshold = args->vacuum_base_threshold;
-       newdbinfo->vacuum_threshold = args->analyze_base_threshold;
-       newdbinfo->dbname = (char *) malloc(strlen(dbname) + 1);
-       strcpy(newdbinfo->dbname, dbname);
-       newdbinfo->username = NULL;
-       if (args->user != NULL)
-       {
-               newdbinfo->username = (char *) malloc(strlen(args->user) + 1);
-               strcpy(newdbinfo->username, args->user);
-       }
-       newdbinfo->password = NULL;
-       if (args->password != NULL)
-       {
-               newdbinfo->password = (char *) malloc(strlen(args->password) + 1);
-               strcpy(newdbinfo->password, args->password);
-       }
-       newdbinfo->oid = oid;
-       newdbinfo->age = age;
-       newdbinfo->table_list = DLNewList();
-       newdbinfo->conn = NULL;
-
-       if (args->debug >= 2)
-               print_table_list(newdbinfo->table_list);
-
-       return newdbinfo;
-}
-
-/* Function adds and removes databases from the db_list as appropriate */
-static void
-update_db_list(Dllist *db_list)
-{
-       int                     disconnect = 0;
-       PGresult   *res = NULL;
-       Dlelem     *db_elem = DLGetHead(db_list);
-       db_info    *dbi = NULL;
-       db_info    *dbi_template1 = DLE_VAL(db_elem);
-       int                     i = 0,
-                               t = 0,
-                               found_match = 0;
-
-       if (args->debug >= 2)
-       {
-               log_entry("updating the database list", LVL_DEBUG);
-               fflush(LOGOUTPUT);
-       }
-
-       if (dbi_template1->conn == NULL)
-       {
-               dbi_template1->conn = db_connect(dbi_template1);
-               disconnect = 1;
-       }
-
-       if (dbi_template1->conn != NULL)
-       {
-               /*
-                * Get a result set that has all the information we will need to
-                * both remove databasews from the list that no longer exist and
-                * add databases to the list that are new
-                */
-               res = send_query(FROZENOID_QUERY2, dbi_template1);
-               if (res != NULL)
-               {
-                       t = PQntuples(res);
-
-                       /*
-                        * First: use the db_list as the outer loop and the result set
-                        * as the inner loop, this will determine what databases
-                        * should be removed
-                        */
-                       while (db_elem != NULL)
-                       {
-                               dbi = ((db_info *) DLE_VAL(db_elem));
-                               found_match = 0;
-
-                               for (i = 0; i < t; i++)
-                               {                               /* loop through result set looking for a
-                                                                * match */
-                                       if (dbi->oid == atooid(PQgetvalue(res, i, PQfnumber(res, "oid"))))
-                                       {
-                                               found_match = 1;
-
-                                               /*
-                                                * update the dbi->age so that we ensure
-                                                * xid_wraparound won't happen
-                                                */
-                                               dbi->age = atol(PQgetvalue(res, i, PQfnumber(res, "age")));
-                                               break;
-                                       }
-                               }
-                               if (found_match == 0)
-                               {                               /* then we didn't find this db_elem in the
-                                                                * result set */
-                                       Dlelem     *elem_to_remove = db_elem;
-
-                                       db_elem = DLGetSucc(db_elem);
-                                       remove_db_from_list(elem_to_remove);
-                               }
-                               else
-                                       db_elem = DLGetSucc(db_elem);
-                       }                                       /* Done removing dropped databases from
-                                                                * the table_list */
-
-                       /*
-                        * Then loop use result set as outer loop and db_list as the
-                        * inner loop to determine what databases are new
-                        */
-                       for (i = 0; i < t; i++)
-                       {
-                               db_elem = DLGetHead(db_list);
-                               found_match = 0;
-                               while (db_elem != NULL)
-                               {
-                                       dbi = ((db_info *) DLE_VAL(db_elem));
-                                       if (dbi->oid == atooid(PQgetvalue(res, i, PQfnumber(res, "oid"))))
-                                       {
-                                               found_match = 1;
-                                               break;
-                                       }
-                                       db_elem = DLGetSucc(db_elem);
-                               }
-                               if (found_match == 0)   /* then we didn't find this result
-                                                                                * now in the tbl_list */
-                               {
-                                       DLAddTail(db_list, DLNewElem(init_dbinfo
-                                                 (PQgetvalue(res, i, PQfnumber(res, "datname")),
-                                          atooid(PQgetvalue(res, i, PQfnumber(res, "oid"))),
-                                         atol(PQgetvalue(res, i, PQfnumber(res, "age"))))));
-                                       if (args->debug >= 1)
-                                       {
-                                               sprintf(logbuffer, "added database: %s", ((db_info *) DLE_VAL(DLGetTail(db_list)))->dbname);
-                                               log_entry(logbuffer, LVL_DEBUG);
-                                       }
-                               }
-                       }                                       /* end of for loop that adds tables */
-               }
-               fflush(LOGOUTPUT);
-               PQclear(res);
-               res = NULL;
-               if (args->debug >= 3)
-                       print_db_list(db_list, 0);
-               if (disconnect)
-                       db_disconnect(dbi_template1);
-       }
-}
-
-/* xid_wraparound_check
-
-From the docs:
-
-With the standard freezing policy, the age column will start at one billion for a
-freshly-vacuumed database. When the age approaches two billion, the database must
-be vacuumed again to avoid risk of wraparound failures. Recommended practice is
-to vacuum each database at least once every half-a-billion (500 million) transactions,
-so as to provide plenty of safety margin.
-
-So we do a full database vacuum if age > 1.5billion
-return 0 if nothing happened,
-return 1 if the database needed a database wide vacuum
-*/
-static int
-xid_wraparound_check(db_info * dbi)
-{
-       /*
-        * FIXME: should probably do something better here so that we don't
-        * vacuum all the databases on the server at the same time.  We have
-        * 500million xacts to work with so we should be able to spread the
-        * load of full database vacuums a bit
-        */
-       if (dbi->age > 1500000000)
-       {
-               PGresult   *res = NULL;
-
-               res = send_query("VACUUM", dbi);
-               /* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
-               if (res != NULL)
-                       PQclear(res);
-               return 1;
-       }
-       return 0;
-}
-
-/* Close DB connection, free memory, and remove the node from the list */
-static void
-remove_db_from_list(Dlelem *db_to_remove)
-{
-       db_info    *dbi = ((db_info *) DLE_VAL(db_to_remove));
-
-       if (args->debug >= 1)
-       {
-               sprintf(logbuffer, "Removing db: %s from list.", dbi->dbname);
-               log_entry(logbuffer, LVL_DEBUG);
-               fflush(LOGOUTPUT);
-       }
-       DLRemove(db_to_remove);
-       if (dbi->conn)
-               db_disconnect(dbi);
-       if (dbi->dbname)
-       {
-               free(dbi->dbname);
-               dbi->dbname = NULL;
-       }
-       if (dbi->username)
-       {
-               free(dbi->username);
-               dbi->username = NULL;
-       }
-       if (dbi->password)
-       {
-               free(dbi->password);
-               dbi->password = NULL;
-       }
-       if (dbi->table_list)
-       {
-               free_tbl_list(dbi->table_list);
-               dbi->table_list = NULL;
-       }
-       if (dbi)
-       {
-               free(dbi);
-               dbi = NULL;
-       }
-       DLFreeElem(db_to_remove);
-}
-
-/* Function is called before program exit to free all memory
-               mostly it's just to keep valgrind happy */
-static void
-free_db_list(Dllist *db_list)
-{
-       Dlelem     *db_elem = DLGetHead(db_list);
-       Dlelem     *db_elem_to_remove = NULL;
-
-       while (db_elem != NULL)
-       {
-               db_elem_to_remove = db_elem;
-               db_elem = DLGetSucc(db_elem);
-               remove_db_from_list(db_elem_to_remove);
-               db_elem_to_remove = NULL;
-       }
-       DLFreeList(db_list);
-}
-
-static void
-print_db_list(Dllist *db_list, int print_table_lists)
-{
-       Dlelem     *db_elem = DLGetHead(db_list);
-
-       while (db_elem != NULL)
-       {
-               print_db_info(((db_info *) DLE_VAL(db_elem)), print_table_lists);
-               db_elem = DLGetSucc(db_elem);
-       }
-}
-
-static void
-print_db_info(db_info * dbi, int print_tbl_list)
-{
-       sprintf(logbuffer, "dbname: %s", (dbi->dbname) ? dbi->dbname : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-
-       sprintf(logbuffer, "  oid: %u", dbi->oid);
-       log_entry(logbuffer, LVL_INFO);
-
-       sprintf(logbuffer, "  username: %s", (dbi->username) ? dbi->username : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-
-       sprintf(logbuffer, "  password: %s", (dbi->password) ? dbi->password : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-
-       if (dbi->conn != NULL)
-               log_entry("  conn is valid, (connected)", LVL_INFO);
-       else
-               log_entry("  conn is null, (not connected)", LVL_INFO);
-
-       sprintf(logbuffer, "  default_analyze_threshold: %li", dbi->analyze_threshold);
-       log_entry(logbuffer, LVL_INFO);
-
-       sprintf(logbuffer, "  default_vacuum_threshold: %li", dbi->vacuum_threshold);
-       log_entry(logbuffer, LVL_INFO);
-
-       fflush(LOGOUTPUT);
-       if (print_tbl_list > 0)
-               print_table_list(dbi->table_list);
-}
-
-/* End of DB List Management Function */
-
-/* Beginning of misc Functions */
-
-/* Perhaps add some test to this function to make sure that the stats we need are available */
-static PGconn *
-db_connect(db_info * dbi)
-{
-       PGconn     *db_conn =
-       PQsetdbLogin(args->host, args->port, NULL, NULL, dbi->dbname,
-                                dbi->username, dbi->password);
-
-       if (PQstatus(db_conn) != CONNECTION_OK)
-       {
-               sprintf(logbuffer, "Failed connection to database %s with error: %s.",
-                               dbi->dbname, PQerrorMessage(db_conn));
-               log_entry(logbuffer, LVL_ERROR);
-               fflush(LOGOUTPUT);
-               PQfinish(db_conn);
-               db_conn = NULL;
-       }
-
-       return db_conn;
-}      /* end of db_connect() */
-
-static void
-db_disconnect(db_info * dbi)
-{
-       if (dbi->conn != NULL)
-       {
-               PQfinish(dbi->conn);
-               dbi->conn = NULL;
-       }
-}
-
-static int
-check_stats_enabled(db_info * dbi)
-{
-       PGresult   *res;
-       int                     ret = 0;
-
-       res = send_query("SHOW stats_row_level", dbi);
-       if (res != NULL)
-       {
-               ret = strcmp("on", PQgetvalue(res, 0, PQfnumber(res, "stats_row_level")));
-               PQclear(res);
-       }
-       return ret;
-}
-
-static PGresult *
-send_query(const char *query, db_info * dbi)
-{
-       PGresult   *res;
-
-       if (dbi->conn == NULL)
-               return NULL;
-
-       if (args->debug >= 4)
-               log_entry(query, LVL_DEBUG);
-
-       res = PQexec(dbi->conn, query);
-
-       if (!res)
-       {
-               sprintf(logbuffer,
-                  "Fatal error occured while sending query (%s) to database %s",
-                               query, dbi->dbname);
-               log_entry(logbuffer, LVL_ERROR);
-               sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
-               log_entry(logbuffer, LVL_EXTRA);
-               fflush(LOGOUTPUT);
-               return NULL;
-       }
-       if (PQresultStatus(res) != PGRES_TUPLES_OK &&
-               PQresultStatus(res) != PGRES_COMMAND_OK)
-       {
-               sprintf(logbuffer,
-                 "Can not refresh statistics information from the database %s.",
-                               dbi->dbname);
-               log_entry(logbuffer, LVL_ERROR);
-               sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
-               log_entry(logbuffer, LVL_EXTRA);
-               fflush(LOGOUTPUT);
-               PQclear(res);
-               return NULL;
-       }
-       return res;
-}      /* End of send_query() */
-
-/*
- * Perform either a vacuum or a vacuum analyze
- */
-static void
-perform_maintenance_command(db_info * dbi, tbl_info * tbl, int operation)
-{
-       char            buf[256];
-
-       /*
-        * Set the vacuum_cost variables if supplied on command line
-        */
-       if (args->av_vacuum_cost_delay != -1)
-       {
-               snprintf(buf, sizeof(buf), "set vacuum_cost_delay = %d",
-                                args->av_vacuum_cost_delay);
-               send_query(buf, dbi);
-       }
-       if (args->av_vacuum_cost_page_hit != -1)
-       {
-               snprintf(buf, sizeof(buf), "set vacuum_cost_page_hit = %d",
-                                args->av_vacuum_cost_page_hit);
-               send_query(buf, dbi);
-       }
-       if (args->av_vacuum_cost_page_miss != -1)
-       {
-               snprintf(buf, sizeof(buf), "set vacuum_cost_page_miss = %d",
-                                args->av_vacuum_cost_page_miss);
-               send_query(buf, dbi);
-       }
-       if (args->av_vacuum_cost_page_dirty != -1)
-       {
-               snprintf(buf, sizeof(buf), "set vacuum_cost_page_dirty = %d",
-                                args->av_vacuum_cost_page_dirty);
-               send_query(buf, dbi);
-       }
-       if (args->av_vacuum_cost_limit != -1)
-       {
-               snprintf(buf, sizeof(buf), "set vacuum_cost_limit = %d",
-                                args->av_vacuum_cost_limit);
-               send_query(buf, dbi);
-       }
-
-       /*
-        * if ((relisshared = t and database != template1) or
-        * if operation = ANALYZE_ONLY)
-        * then only do an analyze
-        */
-       if ((tbl->relisshared > 0 && strcmp("template1", dbi->dbname) != 0) ||
-               (operation == ANALYZE_ONLY))
-               snprintf(buf, sizeof(buf), "ANALYZE %s.%s", dbi->dbname, tbl->table_name);
-       else if (operation == VACUUM_ANALYZE)
-               snprintf(buf, sizeof(buf), "VACUUM ANALYZE %s.%s", dbi->dbname, tbl->table_name);
-       else
-               return;
-
-       if (args->debug >= 1)
-       {
-               sprintf(logbuffer, "Performing: %s on database %s", buf, dbi->dbname);
-               log_entry(logbuffer, LVL_DEBUG);
-               fflush(LOGOUTPUT);
-       }
-
-       send_query(buf, dbi);
-
-       update_table_thresholds(dbi, tbl, operation);
-
-       if (args->debug >= 2)
-               print_table_info(tbl);
-}
-
-static void
-free_cmd_args(void)
-{
-       if (args != NULL)
-       {
-               if (args->user != NULL)
-                       free(args->user);
-               if (args->password != NULL)
-                       free(args->password);
-               free(args);
-       }
-}
-
-static cmd_args *
-get_cmd_args(int argc, char *argv[])
-{
-       int                     c;
-
-       args = (cmd_args *) malloc(sizeof(cmd_args));
-       args->sleep_base_value = SLEEPBASEVALUE;
-       args->sleep_scaling_factor = SLEEPSCALINGFACTOR;
-       args->vacuum_base_threshold = VACBASETHRESHOLD;
-       args->vacuum_scaling_factor = VACSCALINGFACTOR;
-       args->analyze_base_threshold = -1;
-       args->analyze_scaling_factor = -1;
-       args->debug = AUTOVACUUM_DEBUG;
-       args->update_interval = UPDATE_INTERVAL;
-#ifndef WIN32
-       args->daemonize = 0;
-#else
-    args->service_dependencies = 0;
-       args->install_as_service = 0;
-       args->remove_as_service = 0;
-       args->service_user = 0;
-       args->service_password = 0;
-#endif
-       args->user = 0;
-       args->password = 0;
-       args->host = 0;
-       args->logfile = 0;
-       args->port = 0;
-
-       /*
-        * Cost-Based Vacuum Delay Settings for pg_autovacuum
-        */
-       args->av_vacuum_cost_delay = -1;
-       args->av_vacuum_cost_page_hit = -1;
-       args->av_vacuum_cost_page_miss = -1;
-       args->av_vacuum_cost_page_dirty = -1;
-       args->av_vacuum_cost_limit = -1;
-
-       /*
-        * Fixme: Should add some sanity checking such as positive integer
-        * values etc
-        */
-#ifndef WIN32
-       while ((c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hDc:C:m:n:l:")) != -1)
-#else
-       while ((c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hIRN:W:E:c:C:m:n:l:")) != -1)
-#endif
-       {
-               switch (c)
-               {
-                       case 's':
-                               args->sleep_base_value = atoi(optarg);
-                               break;
-                       case 'S':
-                               args->sleep_scaling_factor = atof(optarg);
-                               break;
-                       case 'v':
-                               args->vacuum_base_threshold = atoi(optarg);
-                               break;
-                       case 'V':
-                               args->vacuum_scaling_factor = atof(optarg);
-                               break;
-                       case 'a':
-                               args->analyze_base_threshold = atoi(optarg);
-                               break;
-                       case 'A':
-                               args->analyze_scaling_factor = atof(optarg);
-                               break;
-                       case 'i':
-                               args->update_interval = atoi(optarg);
-                               break;
-                       case 'c':
-                               args->av_vacuum_cost_delay = atoi(optarg);
-                               break;
-                       case 'C':
-                               args->av_vacuum_cost_page_hit = atoi(optarg);
-                               break;
-                       case 'm':
-                               args->av_vacuum_cost_page_miss = atoi(optarg);
-                               break;
-                       case 'n':
-                               args->av_vacuum_cost_page_dirty = atoi(optarg);
-                               break;
-                       case 'l':
-                               args->av_vacuum_cost_limit = atoi(optarg);
-                               break;
-#ifndef WIN32
-                       case 'D':
-                               args->daemonize++;
-                               break;
-#endif
-                       case 'd':
-                               args->debug = atoi(optarg);
-                               break;
-                       case 'U':
-                               args->user = optarg;
-                               break;
-                       case 'P':
-                               args->password = optarg;
-                               break;
-                       case 'H':
-                               args->host = optarg;
-                               break;
-                       case 'L':
-                               args->logfile = optarg;
-                               break;
-                       case 'p':
-                               args->port = optarg;
-                               break;
-                       case 'h':
-                               usage();
-                               exit(0);
-#ifdef WIN32
-                       case 'E':
-                               /*
-                                * CreateService() expects a list of service
-                                * dependencies as a NUL-separated, double-NUL
-                                * terminated list (although we only allow the user to
-                                * specify a single dependency). So we zero out the
-                                * list first, and make sure to leave room for two NUL
-                                * terminators.
-                                */
-                               ZeroMemory(deps, sizeof(deps));
-                               snprintf(deps, sizeof(deps) - 2, "%s", optarg);
-                               args->service_dependencies = deps;
-                               break;
-                       case 'I':
-                               args->install_as_service++;
-                               break;
-                       case 'R':
-                               args->remove_as_service++;
-                               break;
-                       case 'N':
-                               args->service_user = optarg;
-                               break;
-                       case 'W':
-                               args->service_password = optarg;
-                               break;
-#endif
-                       default:
-
-                               /*
-                                * It's here that we know that things are invalid... It is
-                                * not forcibly an error to call usage
-                                */
-                               fprintf(stderr, "Error: Invalid Command Line Options.\n");
-                               usage();
-                               exit(1);
-                               break;
-               }
-
-               /*
-                * if values for insert thresholds are not specified, then they
-                * default to 1/2 of the delete values
-                */
-               if (args->analyze_base_threshold == -1)
-                       args->analyze_base_threshold = args->vacuum_base_threshold / 2;
-               if (args->analyze_scaling_factor == -1)
-                       args->analyze_scaling_factor = args->vacuum_scaling_factor / 2;
-       }
-       return args;
-}
-
-static void
-usage(void)
-{
-       int                     i = 0;
-       float           f = 0;
-
-       fprintf(stderr, "usage: pg_autovacuum \n");
-#ifndef WIN32
-       fprintf(stderr, "   [-D] Daemonize (Detach from tty and run in the background)\n");
-#else
-       fprintf(stderr, "   [-I] Install as a Windows service\n");
-       fprintf(stderr, "   [-R] Remove as a Windows service (all other options will be ignored)\n");
-       fprintf(stderr, "   [-N] Username to run service as (only useful when installing as a Windows service)\n");
-       fprintf(stderr, "   [-W] Password to run service with (only useful when installing as a Windows service)\n");
-       fprintf(stderr, "   [-E] Dependent service that must start before this service (only useful when installing as a Windows service)\n");
-#endif
-       i = AUTOVACUUM_DEBUG;
-       fprintf(stderr, "   [-d] debug (debug level=0,1,2,3; default=%d)\n", i);
-
-       i = SLEEPBASEVALUE;
-       fprintf(stderr, "   [-s] sleep base value (default=%d)\n", i);
-       f = SLEEPSCALINGFACTOR;
-       fprintf(stderr, "   [-S] sleep scaling factor (default=%f)\n", f);
-
-       i = VACBASETHRESHOLD;
-       fprintf(stderr, "   [-v] vacuum base threshold (default=%d)\n", i);
-       f = VACSCALINGFACTOR;
-       fprintf(stderr, "   [-V] vacuum scaling factor (default=%f)\n", f);
-       i = i / 2;
-       fprintf(stderr, "   [-a] analyze base threshold (default=%d)\n", i);
-       f = f / 2;
-       fprintf(stderr, "   [-A] analyze scaling factor (default=%f)\n", f);
-
-       fprintf(stderr, "   [-L] logfile (default=none)\n");
-
-       fprintf(stderr, "   [-c] vacuum_cost_delay (default=none)\n");
-       fprintf(stderr, "   [-C] vacuum_cost_page_hit (default=none)\n");
-       fprintf(stderr, "   [-m] vacuum_cost_page_miss (default=none)\n");
-       fprintf(stderr, "   [-n] vacuum_cost_page_dirty (default=none)\n");
-       fprintf(stderr, "   [-l] vacuum_cost_limit (default=none)\n");
-
-       fprintf(stderr, "   [-U] username (libpq default)\n");
-       fprintf(stderr, "   [-P] password (libpq default)\n");
-       fprintf(stderr, "   [-H] host (libpq default)\n");
-       fprintf(stderr, "   [-p] port (libpq default)\n");
-
-       fprintf(stderr, "   [-h] help (Show this output)\n");
-}
-
-static void
-print_cmd_args(void)
-{
-       sprintf(logbuffer, "Printing command_args");
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->host=%s", (args->host) ? args->host : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->port=%s", (args->port) ? args->port : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->username=%s", (args->user) ? args->user : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->password=%s", (args->password) ? args->password : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->logfile=%s", (args->logfile) ? args->logfile : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-#ifndef WIN32
-       sprintf(logbuffer, "  args->daemonize=%d", args->daemonize);
-       log_entry(logbuffer, LVL_INFO);
-#else
-       sprintf(logbuffer, "  args->install_as_service=%d", args->install_as_service);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->remove_as_service=%d", args->remove_as_service);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->service_dependencies=%s", (args->service_dependencies) ? args->service_dependencies : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->service_user=%s", (args->service_user) ? args->service_user : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->service_password=%s", (args->service_password) ? args->service_password : "(null)");
-       log_entry(logbuffer, LVL_INFO);
-#endif
-
-       sprintf(logbuffer, "  args->sleep_base_value=%d", args->sleep_base_value);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->sleep_scaling_factor=%f", args->sleep_scaling_factor);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->vacuum_base_threshold=%d", args->vacuum_base_threshold);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->vacuum_scaling_factor=%f", args->vacuum_scaling_factor);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->analyze_base_threshold=%d", args->analyze_base_threshold);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->analyze_scaling_factor=%f", args->analyze_scaling_factor);
-       log_entry(logbuffer, LVL_INFO);
-       sprintf(logbuffer, "  args->update_interval=%i", args->update_interval);
-       log_entry(logbuffer, LVL_INFO);
-
-       if (args->av_vacuum_cost_delay != -1)
-               sprintf(logbuffer, "  args->av_vacuum_cost_delay=%d", args->av_vacuum_cost_delay);
-       else
-               sprintf(logbuffer, "  args->av_vacuum_cost_delay=(default)");
-       log_entry(logbuffer, LVL_INFO);
-       if (args->av_vacuum_cost_page_hit != -1)
-               sprintf(logbuffer, "  args->av_vacuum_cost_page_hit=%d", args->av_vacuum_cost_page_hit);
-       else
-               sprintf(logbuffer, "  args->av_vacuum_cost_page_hit=(default)");
-       log_entry(logbuffer, LVL_INFO);
-       if (args->av_vacuum_cost_page_miss != -1)
-               sprintf(logbuffer, "  args->av_vacuum_cost_page_miss=%d", args->av_vacuum_cost_page_miss);
-       else
-               sprintf(logbuffer, "  args->av_vacuum_cost_page_miss=(default)");
-       log_entry(logbuffer, LVL_INFO);
-       if (args->av_vacuum_cost_page_dirty != -1)
-               sprintf(logbuffer, "  args->av_vacuum_cost_page_dirty=%d", args->av_vacuum_cost_page_dirty);
-       else
-               sprintf(logbuffer, "  args->av_vacuum_cost_page_dirty=(default)");
-       log_entry(logbuffer, LVL_INFO);
-       if (args->av_vacuum_cost_limit != -1)
-               sprintf(logbuffer, "  args->av_vacuum_cost_limit=%d", args->av_vacuum_cost_limit);
-       else
-               sprintf(logbuffer, "  args->av_vacuum_cost_limit=(default)");
-       log_entry(logbuffer, LVL_INFO);
-
-       sprintf(logbuffer, "  args->debug=%d", args->debug);
-       log_entry(logbuffer, LVL_INFO);
-
-       fflush(LOGOUTPUT);
-}
-
-#ifdef WIN32
-
-/* Handle control requests from the Service Control Manager */
-static void
-ControlHandler(DWORD request)
-{
-       switch (request)
-       {
-               case SERVICE_CONTROL_STOP:
-               case SERVICE_CONTROL_SHUTDOWN:
-                       log_entry("pg_autovacuum service stopping...", LVL_INFO);
-                       fflush(LOGOUTPUT);
-                       ServiceStatus.dwWin32ExitCode = 0;
-                       ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-                       SetServiceStatus(hStatus, &ServiceStatus);
-                       return;
-
-               default:
-                       break;
-       }
-
-       /* Report current status */
-       SetServiceStatus(hStatus, &ServiceStatus);
-
-       return;
-}
-
-/* Register with the Service Control Manager */
-static int
-InstallService(void)
-{
-       SC_HANDLE       schService = NULL;
-       SC_HANDLE       schSCManager = NULL;
-       char            szFilename[MAX_PATH],
-                               szKey[MAX_PATH],
-                               szCommand[MAX_PATH + 1024],
-                               szMsgDLL[MAX_PATH];
-       HKEY            hk = NULL;
-       DWORD           dwData = 0;
-
-       /*
-        * Register the service with the SCM
-        */
-       GetModuleFileName(NULL, szFilename, MAX_PATH);
-
-       /* Open the Service Control Manager on the local computer. */
-       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-       if (!schSCManager)
-               return -1;
-
-       schService = CreateService(
-                                                          schSCManager,        /* SCManager database */
-                                                          TEXT("pg_autovacuum"),       /* Name of service */
-                                                          TEXT("PostgreSQL Auto Vacuum"),      /* Name to display */
-                                                          SERVICE_ALL_ACCESS,          /* Desired access */
-                                                          SERVICE_WIN32_OWN_PROCESS,           /* Service type */
-                                                          SERVICE_AUTO_START,          /* Start type */
-                                                          SERVICE_ERROR_NORMAL,        /* Error control type */
-                                                          szFilename,          /* Service binary */
-                                                          NULL,        /* No load ordering group */
-                                                          NULL,        /* No tag identifier */
-                                                          args->service_dependencies,  /* Dependencies */
-                                                          args->service_user,          /* Service account */
-                                                          args->service_password); /* Account password */
-
-       if (!schService)
-               return -2;
-
-       /*
-        * Rewrite the command line for the service
-        */
-       sprintf(szKey, "SYSTEM\\CurrentControlSet\\Services\\pg_autovacuum");
-       if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_ALL_ACCESS, &hk))
-               return -3;
-
-       /* Build the command line */
-       sprintf(szCommand, "\"%s\"", szFilename);
-       if (args->host)
-               sprintf(szCommand, "%s -H %s", szCommand, args->host);
-       if (args->port)
-               sprintf(szCommand, "%s -p %s", szCommand, args->port);
-       if (args->user)
-               sprintf(szCommand, "%s -U \"%s\"", szCommand, args->user);
-       if (args->password)
-               sprintf(szCommand, "%s -P \"%s\"", szCommand, args->password);
-       if (args->logfile)
-               sprintf(szCommand, "%s -L \"%s\"", szCommand, args->logfile);
-       if (args->sleep_base_value != (int) SLEEPBASEVALUE)
-               sprintf(szCommand, "%s -s %d", szCommand, args->sleep_base_value);
-       if (args->sleep_scaling_factor != (float) SLEEPSCALINGFACTOR)
-               sprintf(szCommand, "%s -S %f", szCommand, args->sleep_scaling_factor);
-       if (args->vacuum_base_threshold != (int) VACBASETHRESHOLD)
-               sprintf(szCommand, "%s -v %d", szCommand, args->vacuum_base_threshold);
-       if (args->vacuum_scaling_factor != (float) VACSCALINGFACTOR)
-               sprintf(szCommand, "%s -V %f", szCommand, args->vacuum_scaling_factor);
-       if (args->analyze_base_threshold != (int) (VACBASETHRESHOLD / 2))
-               sprintf(szCommand, "%s -a %d", szCommand, args->analyze_base_threshold);
-       if (args->analyze_scaling_factor != (float) (VACSCALINGFACTOR / 2))
-               sprintf(szCommand, "%s -A %f", szCommand, args->analyze_scaling_factor);
-       if (args->debug != (int) AUTOVACUUM_DEBUG)
-               sprintf(szCommand, "%s -d %d", szCommand, args->debug);
-       if (args->av_vacuum_cost_delay != -1)
-               sprintf(szCommand, "%s -d %d", szCommand, args->av_vacuum_cost_delay);
-       if (args->av_vacuum_cost_page_hit != -1)
-               sprintf(szCommand, "%s -d %d", szCommand, args->av_vacuum_cost_page_hit);
-       if (args->av_vacuum_cost_page_miss != -1)
-               sprintf(szCommand, "%s -d %d", szCommand, args->av_vacuum_cost_page_miss);
-       if (args->av_vacuum_cost_page_dirty != -1)
-               sprintf(szCommand, "%s -d %d", szCommand, args->av_vacuum_cost_page_dirty);
-       if (args->av_vacuum_cost_limit != -1)
-               sprintf(szCommand, "%s -d %d", szCommand, args->av_vacuum_cost_limit);
-
-       /* And write the new value */
-       if (RegSetValueEx(hk, "ImagePath", 0, REG_EXPAND_SZ, (LPBYTE) szCommand, (DWORD) strlen(szCommand) + 1))
-               return -4;
-       RegCloseKey(hk);
-
-       /*
-        * Set the Event source for the application log
-        */
-       sprintf(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\PostgreSQL Auto Vacuum");
-       if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hk, NULL))
-               return -5;
-
-       /* TODO Try to find pgevent.dll, rather than hope it's in the path. ! */
-       /* Message DLL */
-       sprintf(szMsgDLL, "pgevent.dll");
-       if (RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) szMsgDLL, (DWORD) strlen(szMsgDLL) + 1))
-               return -6;
-
-       /* Set the event types supported */
-       dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE | EVENTLOG_SUCCESS;
-       if (RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE) & dwData, sizeof(DWORD)))
-               return -9;
-
-       RegCloseKey(hk);
-       return 0;
-}
-
-/* Unregister from the Service Control Manager */
-static int
-RemoveService(void)
-{
-       SC_HANDLE       schService = NULL;
-       SC_HANDLE       schSCManager = NULL;
-       char            szKey[MAX_PATH];
-       HKEY            hk = NULL;
-
-       /* Open the SCM */
-       schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-       if (!schSCManager)
-               return -1;
-
-       /* Open the service */
-       schService = OpenService(schSCManager, TEXT("pg_autovacuum"), SC_MANAGER_ALL_ACCESS);
-       if (!schService)
-               return -2;
-
-       /* Now delete the service */
-       if (!DeleteService(schService))
-               return -3;
-
-       /*
-        * Remove the Event source from the application log
-        */
-       sprintf(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application");
-       if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_ALL_ACCESS, &hk))
-               return -4;
-       if (RegDeleteKey(hk, "PostgreSQL Auto Vacuum"))
-               return -5;
-
-       return 0;
-}
-#endif   /* WIN32 */
-
-static
-int
-VacuumLoop(int argc, char **argv)
-{
-       int                     j = 0,
-                               loops = 0;
-
-       /* int numInserts, numDeletes, */
-       int                     sleep_secs;
-       Dllist     *db_list;
-       Dlelem     *db_elem,
-                          *tbl_elem;
-       db_info    *dbs;
-       tbl_info   *tbl;
-       PGresult   *res = NULL;
-       double          diff;
-
-       struct timeval now,
-                               then;
-
-#ifdef WIN32
-
-       if (appMode)
-               log_entry("pg_autovacuum starting in Windows Application mode", LVL_INFO);
-       else
-               log_entry("pg_autovacuum starting in Windows Service mode", LVL_INFO);
-
-       ServiceStatus.dwServiceType = SERVICE_WIN32;
-       ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
-       ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
-       ServiceStatus.dwWin32ExitCode = 0;
-       ServiceStatus.dwServiceSpecificExitCode = 0;
-       ServiceStatus.dwCheckPoint = 0;
-       ServiceStatus.dwWaitHint = 0;
-
-       if (!appMode)
-       {
-               hStatus = RegisterServiceCtrlHandler("pg_autovacuum", (LPHANDLER_FUNCTION) ControlHandler);
-               if (hStatus == (SERVICE_STATUS_HANDLE) 0)
-                       return -1;
-       }
-#endif   /* WIN32 */
-
-       /* Init the db list with template1 */
-       db_list = init_db_list();
-       if (db_list == NULL)
-               return 1;
-
-       if (check_stats_enabled(((db_info *) DLE_VAL(DLGetHead(db_list)))) != 0)
-       {
-               log_entry("GUC variable stats_row_level must be enabled.", LVL_ERROR);
-               log_entry("       Please fix the problems and try again.", LVL_EXTRA);
-               fflush(LOGOUTPUT);
-
-               exit(1);
-       }
-
-       gettimeofday(&then, 0);         /* for use later to caluculate sleep time */
-
-#ifndef WIN32
-       while (1)
-#else
-       /* We can now report the running status to SCM. */
-       ServiceStatus.dwCurrentState = SERVICE_RUNNING;
-       if (!appMode)
-               SetServiceStatus(hStatus, &ServiceStatus);
-
-       while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
-#endif
-       {
-               /* Main Loop */
-
-               db_elem = DLGetHead(db_list);   /* Reset cur_db_node to the
-                                                                                * beginning of the db_list */
-
-               dbs = ((db_info *) DLE_VAL(db_elem));   /* get pointer to cur_db's
-                                                                                                * db_info struct */
-               if (dbs->conn == NULL)
-               {
-                       dbs->conn = db_connect(dbs);
-                       if (dbs->conn == NULL)
-                       {                                       /* Serious problem: We can't connect to
-                                                                * template1 */
-                               log_entry("Cannot connect to template1, exiting.", LVL_ERROR);
-                               fflush(LOGOUTPUT);
-                               fclose(LOGOUTPUT);
-#ifdef WIN32
-                               ServiceStatus.dwCurrentState = SERVICE_STOPPED;
-                               ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
-                               ServiceStatus.dwServiceSpecificExitCode = -1;
-                               if (!appMode)
-                                       SetServiceStatus(hStatus, &ServiceStatus);
-#endif
-                               exit(1);
-                       }
-               }
-
-               if (loops % args->update_interval == 0)         /* Update the list if it's
-                                                                                                        * time */
-                       update_db_list(db_list);        /* Add and remove databases from
-                                                                                * the list */
-
-               while (db_elem != NULL)
-               {                                               /* Loop through databases in list */
-                       dbs = ((db_info *) DLE_VAL(db_elem));           /* get pointer to
-                                                                                                                * cur_db's db_info
-                                                                                                                * struct */
-                       if (dbs->conn == NULL)
-                               dbs->conn = db_connect(dbs);
-
-                       if (dbs->conn != NULL)
-                       {
-                               if (loops % args->update_interval == 0)         /* Update the list if
-                                                                                                                        * it's time */
-                                       update_table_list(dbs);         /* Add and remove tables
-                                                                                                * from the list */
-
-                               if (xid_wraparound_check(dbs) == 0)
-                               {
-                                       res = send_query(TABLE_STATS_QUERY, dbs);       /* Get an updated
-                                                                                                                                * snapshot of this dbs
-                                                                                                                                * table stats */
-                                       if (res != NULL)
-                                       {
-                                               for (j = 0; j < PQntuples(res); j++)
-                                               {               /* loop through result set */
-                                                       tbl_elem = DLGetHead(dbs->table_list);          /* Reset tbl_elem to top
-                                                                                                                                                * of dbs->table_list */
-                                                       while (tbl_elem != NULL)
-                                                       {       /* Loop through tables in list */
-                                                               tbl = ((tbl_info *) DLE_VAL(tbl_elem)); /* set tbl_info =
-                                                                                                                                                * current_table */
-                                                               if (tbl->relid == atooid(PQgetvalue(res, j, PQfnumber(res, "oid"))))
-                                                               {
-                                                                       tbl->curr_analyze_count =
-                                                                               (atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_ins"))) +
-                                                                                atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_upd"))) +
-                                                                                atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_del"))));
-                                                                       tbl->curr_vacuum_count =
-                                                                               (atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_del"))) +
-                                                                                atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_upd"))));
-
-                                                                       /*
-                                                                        * Check numDeletes to see if we need
-                                                                        * to vacuum, if so: Run vacuum
-                                                                        * analyze (adding analyze is small so
-                                                                        * we might as well) Update table
-                                                                        * thresholds and related information
-                                                                        * if numDeletes is not big enough for
-                                                                        * vacuum then check numInserts for
-                                                                        * analyze
-                                                                        */
-                                                                       if (tbl->curr_vacuum_count - tbl->CountAtLastVacuum >= tbl->vacuum_threshold)
-                                                                               perform_maintenance_command(dbs, tbl, VACUUM_ANALYZE);
-                                                                       else if (tbl->curr_analyze_count - tbl->CountAtLastAnalyze >= tbl->analyze_threshold)
-                                                                               perform_maintenance_command(dbs, tbl, ANALYZE_ONLY);
-
-                                                                       break;          /* We found a match, no need to keep looping. */
-                                                               }
-
-                                                               /*
-                                                                * Advance the table pointers for the next
-                                                                * loop
-                                                                */
-                                                               tbl_elem = DLGetSucc(tbl_elem);
-
-                                                       }       /* end for table while loop */
-                                               }               /* end for j loop (tuples in PGresult) */
-                                       }                       /* end if (res != NULL) */
-                               }                               /* close of if (xid_wraparound_check()) */
-                               /* Done working on this db, Clean up, then advance cur_db */
-                               PQclear(res);
-                               res = NULL;
-                               db_disconnect(dbs);
-                       }
-                       db_elem = DLGetSucc(db_elem);           /* move on to next DB
-                                                                                                * regardless */
-               }                                               /* end of db_list while loop */
-
-               /* Figure out how long to sleep etc ... */
-               gettimeofday(&now, 0);
-               diff = (int) (now.tv_sec - then.tv_sec) * 1000000.0 + (int) (now.tv_usec - then.tv_usec);
-
-               sleep_secs = args->sleep_base_value + args->sleep_scaling_factor * diff / 1000000.0;
-               loops++;
-               if (args->debug >= 2)
-               {
-                       sprintf(logbuffer,
-                        "%d All DBs checked in: %.0f usec, will sleep for %d secs.",
-                                       loops, diff, sleep_secs);
-                       log_entry(logbuffer, LVL_DEBUG);
-                       fflush(LOGOUTPUT);
-               }
-
-               /* Larger Pause between outer loops */
-               /*
-                *      pg_usleep() is wrong here because its maximum is ~2000 seconds,
-                *      and we don't need signal interruptability on Win32 here.
-                */
-#ifndef WIN32
-               sleep(sleep_secs);                      /* Unix sleep is seconds */
-#else
-               sleep(sleep_secs * 1000);       /* Win32 sleep() is milliseconds */
-#endif
-
-               gettimeofday(&then, 0); /* Reset time counter */
-
-       }                                                       /* end of while loop */
-
-       /*
-        * program is exiting, this should never run, but is here to make
-        * compiler / valgrind happy
-        */
-       free_db_list(db_list);
-       free_cmd_args();
-       return 0;
-}
-
-/* Beginning of AutoVacuum Main Program */
-int
-main(int argc, char *argv[])
-{
-
-#ifdef WIN32
-       LPVOID          lpMsgBuf;
-       SERVICE_TABLE_ENTRY ServiceTable[2];
-#endif
-
-       args = get_cmd_args(argc, argv);        /* Get Command Line Args and put
-                                                                                * them in the args struct */
-#ifndef WIN32
-       /* Dameonize if requested */
-       if (args->daemonize == 1)
-               daemonize();
-#endif
-
-       if (args->logfile)
-       {
-               LOGOUTPUT = fopen(args->logfile, "a");
-               if (!LOGOUTPUT)
-               {
-                       fprintf(stderr, "Could not open log file - [%s]\n", args->logfile);
-                       exit(-1);
-               }
-       }
-       else
-               LOGOUTPUT = stderr;
-       if (args->debug >= 2)
-               print_cmd_args();
-
-#ifdef WIN32
-       /* Install as a Windows service if required */
-       if (args->install_as_service)
-       {
-               if (InstallService() != 0)
-               {
-                       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpMsgBuf, 0, NULL);
-            fprintf(stderr, "Error: %s\n", (char *) lpMsgBuf);
-                       exit(-1);
-               }
-               else
-               {
-                       fprintf(stderr, "Successfully installed pg_autovacuum as a service.\n");
-                       exit(0);
-               }
-       }
-
-       /* Remove as a Windows service if required */
-       if (args->remove_as_service)
-       {
-               if (RemoveService() != 0)
-               {
-                       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpMsgBuf, 0, NULL);
-            fprintf(stderr, "Error: %s\n", (char *) lpMsgBuf);
-                       exit(-1);
-               }
-               else
-               {
-                       fprintf(stderr, "Successfully removed pg_autovacuum as a service.\n");
-                       exit(0);
-               }
-       }
-
-       /* Normal service startup */
-       ServiceTable[0].lpServiceName = "pg_autovacuum";
-       ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION) VacuumLoop;
-
-       ServiceTable[1].lpServiceName = NULL;
-       ServiceTable[1].lpServiceProc = NULL;
-
-       /* Start the control dispatcher thread for our service */
-       if (!StartServiceCtrlDispatcher(ServiceTable))
-       {
-               appMode = 1;
-               VacuumLoop(0, NULL);
-       }
-
-#else                                                  /* Unix */
-
-       /* Call the main program loop. */
-       VacuumLoop(0, NULL);
-#endif   /* WIN32 */
-
-       return EXIT_SUCCESS;
-}
diff --git a/contrib/pg_autovacuum/pg_autovacuum.h b/contrib/pg_autovacuum/pg_autovacuum.h
deleted file mode 100644 (file)
index 5c6186d..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* pg_autovacuum.h
- * Header file for pg_autovacuum.c
- * (c) 2003 Matthew T. O'Connor
- *
- * $PostgreSQL: pgsql/contrib/pg_autovacuum/pg_autovacuum.h,v 1.15 2005/04/19 03:35:15 momjian Exp $
- */
-
-#ifndef _PG_AUTOVACUUM_H
-#define _PG_AUTOVACUUM_H
-
-#include "libpq-fe.h"
-#include "lib/dllist.h"
-
-#define AUTOVACUUM_DEBUG       0
-#define VACBASETHRESHOLD       1000
-#define VACSCALINGFACTOR       2
-#define SLEEPBASEVALUE         300
-#define SLEEPSCALINGFACTOR     2
-#define UPDATE_INTERVAL                2
-
-/* these two constants are used to tell update_table_stats what operation we just perfomred */
-#define VACUUM_ANALYZE         0
-#define ANALYZE_ONLY           1
-
-
-#define TABLE_STATS_QUERY      "select a.oid,a.relname,a.relnamespace,a.relpages,a.relisshared,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del from pg_class a, pg_stat_all_tables b where a.oid=b.relid and a.relkind = 'r'"
-
-#define PAGES_QUERY "select oid,reltuples,relpages from pg_class where oid=%u"
-#define FROZENOID_QUERY "select oid,age(datfrozenxid) from pg_database where datname = 'template1'"
-#define FROZENOID_QUERY2 "select oid,datname,age(datfrozenxid) from pg_database where datname!='template0'"
-
-/* Log levels */
-enum
-{
-       LVL_DEBUG = 1,
-       LVL_INFO,
-       LVL_WARNING,
-       LVL_ERROR,
-       LVL_EXTRA
-};
-
-/* define cmd_args stucture */
-typedef struct cmdargs
-{
-       int                     vacuum_base_threshold,
-                               analyze_base_threshold,
-                               update_interval,
-                               sleep_base_value,
-                               debug,
-                               
-                               /*
-                                * Cost-Based Vacuum Delay Settings for pg_autovacuum
-                                */
-                               av_vacuum_cost_delay,
-                               av_vacuum_cost_page_hit,
-                               av_vacuum_cost_page_miss,
-                               av_vacuum_cost_page_dirty,
-                               av_vacuum_cost_limit,
-                               
-#ifndef WIN32
-                               daemonize;
-#else
-                               install_as_service,
-                               remove_as_service;
-#endif
-       float           vacuum_scaling_factor,
-                               analyze_scaling_factor,
-                               sleep_scaling_factor;
-       char       *user,
-                          *password,
-#ifdef WIN32
-                          *service_dependencies,
-                          *service_user,
-                          *service_password,
-#endif
-                          *host,
-                          *logfile,
-                          *port;
-} cmd_args;
-
-/*
- * Might need to add a time value for last time the whole database was
- * vacuumed.  We need to guarantee this happens approx every 1Billion TX's
- */
-typedef struct dbinfo
-{
-       Oid                     oid;
-       long            age;
-       long            analyze_threshold,
-                               vacuum_threshold;               /* Use these as defaults for table
-                                                                                * thresholds */
-       PGconn     *conn;
-       char       *dbname,
-                          *username,
-                          *password;
-       Dllist     *table_list;
-} db_info;
-
-typedef struct tableinfo
-{
-       char       *schema_name,
-                          *table_name;
-       float           reltuples;
-       int                     relisshared;
-       Oid                     relid,
-                               relpages;
-       long            analyze_threshold,
-                               vacuum_threshold;
-       long            CountAtLastAnalyze;             /* equal to: inserts + updates as
-                                                                                * of the last analyze or initial
-                                                                                * values at startup */
-       long            CountAtLastVacuum;              /* equal to: deletes + updates as
-                                                                                * of the last vacuum or initial
-                                                                                * values at startup */
-       long            curr_analyze_count,
-                               curr_vacuum_count;              /* Latest values from stats system */
-       db_info    *dbi;                        /* pointer to the database that this table
-                                                                * belongs to */
-} tbl_info;
-
-#endif /* _PG_AUTOVACUUM_H */