*** ./src/backend/bootstrap/bootstrap.c.orig	2004-06-16 01:54:54.847325581 -0400
--- ./src/backend/bootstrap/bootstrap.c	2004-06-16 01:22:05.607171281 -0400
***************
*** 34,39 ****
--- 34,40 ----
  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
  #include "postmaster/bgwriter.h"
+ #include "postmaster/pg_autovacuum.h"
  #include "storage/freespace.h"
  #include "storage/ipc.h"
  #include "storage/pg_shmem.h"
***************
*** 358,363 ****
--- 359,367 ----
  			case BS_XLOG_BGWRITER:
  				statmsg = "writer process";
  				break;
+ 			case BS_XLOG_AUTOVAC:
+ 				statmsg = "auto vacuum process";
+ 				break;
  			default:
  				statmsg = "??? process";
  				break;
***************
*** 394,399 ****
--- 398,406 ----
  			case BS_XLOG_BGWRITER:
  				InitDummyProcess(DUMMY_PROC_BGWRITER);
  				break;
+ 			case BS_XLOG_AUTOVAC:
+ 				InitDummyProcess(DUMMY_PROC_AUTOVAC);
+ 				break;
  
  			default:
  				InitDummyProcess(DUMMY_PROC_DEFAULT);
***************
*** 430,435 ****
--- 437,448 ----
  			BackgroundWriterMain();
  			proc_exit(1);		/* should never return */
  
+ 		case BS_XLOG_AUTOVAC:
+ 			/* don't set signals, autovac has its own agenda */
+ 			InitXLOGAccess();
+ 			AutoVacMain();
+ 			proc_exit(1);		/* should never return */
+ 		
  		default:
  			elog(PANIC, "unrecognized XLOG op: %d", xlogop);
  			proc_exit(1);
*** ./src/backend/catalog/Makefile.orig	2004-06-10 23:40:08.000000000 -0400
--- ./src/backend/catalog/Makefile	2004-06-10 23:40:28.000000000 -0400
***************
*** 32,38 ****
  	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
  	pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
  	pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
! 	pg_depend.h indexing.h \
      )
  
  pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
--- 32,38 ----
  	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
  	pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
  	pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
! 	pg_depend.h pg_autovacuum.h indexing.h \
      )
  
  pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
*** ./src/backend/Makefile.orig	2004-06-07 01:21:43.000000000 -0400
--- ./src/backend/Makefile	2004-06-05 13:46:24.000000000 -0400
***************
*** 29,41 ****
  
  ##########################################################################
  
! all: submake-libpgport postgres $(POSTGRES_IMP)
  
  ifneq ($(PORTNAME), cygwin)
  ifneq ($(PORTNAME), win32)
  
  postgres: $(OBJS)
! 	$(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $^ $(LIBS) -o $@
  
  endif
  endif
--- 29,41 ----
  
  ##########################################################################
  
! all: submake-libpgport submake-libpq postgres $(POSTGRES_IMP)
  
  ifneq ($(PORTNAME), cygwin)
  ifneq ($(PORTNAME), win32)
  
  postgres: $(OBJS)
! 	$(CC) $(CFLAGS) $(LDFLAGS) -I $(libpq_srcdir) $(export_dynamic) $^ $(LIBS)  $(libpq) -o $@
  
  endif
  endif
*** ./src/backend/postmaster/Makefile.orig	2004-06-05 00:58:08.000000000 -0400
--- ./src/backend/postmaster/Makefile	2004-06-05 13:45:20.000000000 -0400
***************
*** 12,18 ****
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = postmaster.o bgwriter.o pgstat.o
  
  all: SUBSYS.o
  
--- 12,18 ----
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = postmaster.o bgwriter.o pgstat.o pg_autovacuum.o
  
  all: SUBSYS.o
  
*** ./src/backend/postmaster/pg_autovacuum.c.orig	2004-06-07 00:39:57.000000000 -0400
--- ./src/backend/postmaster/pg_autovacuum.c	2004-06-16 00:29:06.000000000 -0400
***************
*** 1,153 ****
! /* pg_autovacuum.c
   * All the code for the pg_autovacuum program
   * (c) 2003 Matthew T. O'Connor
   * Revisions by Christopher B. Browne, Liberty RMS
   */
  
! #include "pg_autovacuum.h"
  
- FILE	   *LOGOUTPUT;
  char		logbuffer[4096];
  
! static void
! log_entry(const char *logentry)
! {
! 	time_t		curtime;
! 	struct tm  *loctime;
! 	char		timebuffer[128];
! 
! 	curtime = time(NULL);
! 	loctime = localtime(&curtime);
! 	strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S %Z", loctime);
! 	fprintf(LOGOUTPUT, "[%s] %s\n", timebuffer, logentry);
! }
  
  /*
!  * Function used to detach the pg_autovacuum daemon from the tty and go into
!  * the background.
!  *
!  * This code is mostly ripped directly from pm_dameonize in postmaster.c with
!  * unneeded code removed.
   */
! static void
! daemonize()
! {
! 	pid_t		pid;
  
! 	pid = fork();
! 	if (pid == (pid_t) -1)
! 	{
! 		log_entry("Error: cannot disassociate from controlling TTY");
! 		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("Error: cannot disassociate from controlling TTY");
- 		fflush(LOGOUTPUT);
- 		_exit(1);
- 	}
- #endif
  
! }
  
! /* 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");
! 		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");
! 		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");
! 		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)
  	{
--- 1,220 ----
! /*-------------------------------------------------------------------------
!  *
!  * pg_autovacuum.c
!  *
!  * The background autovacuum daemon was in 7.4 contribis but is being newly 
!  * integrated into 7.5.  It monitors database activity using data from the 
!  * stats system (though at some point is should also look at FSM data) so 
!  * as to perform vacuum commands on specific tables when and only when 
!  * a sufficient amount activity has been performed on that table.
!  *
!  * The autovacuum process is started by the postmaster on startup.
!  * It remains alive until the postmaster commands it to terminate. Normal 
!  * termination is by SIGUSR2, which instructs the autovacuum process to exit(0).  
!  * Emergency termination is by SIGQUIT; like any
!  * backend, the autovacuum process will simply abort and exit on SIGQUIT.
!  *
   * All the code for the pg_autovacuum program
   * (c) 2003 Matthew T. O'Connor
   * Revisions by Christopher B. Browne, Liberty RMS
+  *-------------------------------------------------------------------------
   */
+ #include "postgres.h"
  
! #include <signal.h>
! #include <time.h>
! 
! #include "access/xlog.h"
! #include "libpq/pqsignal.h"
! #include "miscadmin.h"
! #include "postmaster/bgwriter.h"
! #include "storage/bufmgr.h"
! #include "storage/freespace.h"
! #include "storage/ipc.h"
! #include "storage/pmsignal.h"
! #include "storage/smgr.h"
! #include "tcop/tcopprot.h"
! #include "utils/guc.h"
! #include "postmaster/pg_autovacuum.h"
  
  char		logbuffer[4096];
  
! /*
!  * GUC parameters
!  */
! bool		autovac_start_daemon = true;
! 
  
  /*
!  * Flags set by interrupt handlers for later service in the main loop.
   */
! static volatile sig_atomic_t got_SIGHUP = false;
! static volatile sig_atomic_t shutdown_requested = false;
  
! /*
!  * Private state
!  */
! static bool		am_autovac = false;
  
  
! static void autovac_quickdie(SIGNAL_ARGS);
! static void AutoVacSigHupHandler(SIGNAL_ARGS);
! static void ReqShutdownHandler(SIGNAL_ARGS);
! 
  
! /*
!  * Main entry point for bgwriter process
!  *
!  * This is invoked from BootstrapMain, which has already created the basic
!  * execution environment, but not enabled signals yet.
!  */
! void
! AutoVacMain(void)
  {
! 	am_autovac = true;
  
! 	/*
! 	 * Properly accept or ignore signals the postmaster might send us
! 	 *
! 	 * Note: we deliberately ignore SIGTERM, because during a standard Unix
! 	 * system shutdown cycle, init will SIGTERM all processes at once.  We
! 	 * want to wait for the backends to exit, whereupon the postmaster will
! 	 * tell us it's okay to shut down (via SIGUSR2).
! 	 *
! 	 * SIGUSR1 is presently unused; keep it spare in case someday we want
! 	 * this process to participate in sinval messaging.
! 	 */
! 	pqsignal(SIGHUP, AutoVacSigHupHandler);	/* set flag to read config file */
! 	pqsignal(SIGTERM, SIG_IGN);			/* ignore SIGTERM */
! 	pqsignal(SIGQUIT, autovac_quickdie);		/* hard crash time */
! 	pqsignal(SIGALRM, SIG_IGN);
! 	pqsignal(SIGPIPE, SIG_IGN);
! 	pqsignal(SIGUSR1, SIG_IGN);			/* reserve for sinval */
! 	pqsignal(SIGUSR2, ReqShutdownHandler);		/* request shutdown */
! 
! 	/*
! 	 * Reset some signals that are accepted by postmaster but not here
! 	 */
! 	pqsignal(SIGCHLD, SIG_DFL);
! 	pqsignal(SIGTTIN, SIG_DFL);
! 	pqsignal(SIGTTOU, SIG_DFL);
! 	pqsignal(SIGCONT, SIG_DFL);
! 	pqsignal(SIGWINCH, SIG_DFL);
! 
! 	/* We allow SIGQUIT (quickdie) at all times */
! #ifdef HAVE_SIGPROCMASK
! 	sigdelset(&BlockSig, SIGQUIT);
! #else
! 	BlockSig &= ~(sigmask(SIGQUIT));
! #endif
! 
! 	/*
! 	 * If an exception is encountered, processing resumes here.
! 	 */
! 	if (sigsetjmp(Warn_restart, 1) != 0)
  	{
! 		/*
! 		 * Make sure we're not interrupted while cleaning up.  Also forget
! 		 * any pending QueryCancel request, since we're aborting anyway.
! 		 * Force InterruptHoldoffCount to a known state in case we
! 		 * ereport'd from inside a holdoff section.
! 		 */
! 		ImmediateInterruptOK = false;
! 		QueryCancelPending = false;
! 		InterruptHoldoffCount = 1;
! 		CritSectionCount = 0;	/* should be unnecessary, but... */
  
! 		/*
! 		 * These operations are really just a minimal subset of
! 		 * AbortTransaction().  We don't have very many resources
! 		 * to worry about in bgwriter, but we do have LWLocks and buffers.
! 		 */
! 		LWLockReleaseAll();
! 		AbortBufferIO();
! 		UnlockBuffers();
  
! 		/*
! 		 * Clear flag to indicate that we got out of error recovery mode
! 		 * successfully.  (Flag was set in elog.c before longjmp().)
! 		 */
! 		InError = false;
  
! 		/*
! 		 * Exit interrupt holdoff section we implicitly established above.
! 		 */
! 		RESUME_INTERRUPTS();
  
! 		/*
! 		 * Sleep at least 1 second after any error.  A write error is
! 		 * likely to be repeated, and we don't want to be filling the
! 		 * error logs as fast as we can.  (XXX think about ways to make
! 		 * progress when the LRU dirty buffer cannot be written...)
! 		 */
! 		pg_usleep(1000000L);
  	}
  
+ 	Warn_restart_ready = true;	/* we can now handle ereport(ERROR) */
+ 
  	/*
! 	 * Unblock signals (they were blocked when the postmaster forked us)
  	 */
! 	PG_SETMASK(&UnBlockSig);
  
! 	AutoVacLoop();
! }
! 
! 
! /* --------------------------------
!  *		signal handler routines
!  * --------------------------------
!  */
! 
! /*
!  * autovac_quickdie() occurs when signalled SIGQUIT by the postmaster.
!  *
!  * Some backend has bought the farm,
!  * so we need to stop what we're doing and exit.
!  */
! static void
! autovac_quickdie(SIGNAL_ARGS)
! {
! 	PG_SETMASK(&BlockSig);
  
! 	/*
! 	 * DO NOT proc_exit() -- we're here because shared memory may be
! 	 * corrupted, so we don't want to try to clean up our transaction.
! 	 * Just nail the windows shut and get out of town.
! 	 *
! 	 * Note we do exit(1) not exit(0).	This is to force the postmaster into
! 	 * a system reset cycle if some idiot DBA sends a manual SIGQUIT to a
! 	 * random backend.	This is necessary precisely because we don't clean
! 	 * up our shared memory state.
! 	 */
! 	exit(1);
! }
  
! /* SIGHUP: set flag to re-read config file at next convenient time */
! static void
! AutoVacSigHupHandler(SIGNAL_ARGS)
! {
! 	got_SIGHUP = true;
! }
  
! /* SIGUSR2: set flag to run a shutdown checkpoint and exit */
! static void
! ReqShutdownHandler(SIGNAL_ARGS)
! {
! 	shutdown_requested = true;
  }
  
+ 
  /* 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, Oid table_oid, int vacuum_type)
  {
  	int			disconnect = 0;
! 	char		query[255];
  
  	if (dbi->conn == NULL)
  	{
***************
*** 157,215 ****
  
  	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)
  	{
--- 224,276 ----
  
  	if (dbi->conn != NULL)
  	{
! 		/*
! 		* update vacuum and analyze thresholds if 
! 		* we did a vacuum analyze
! 		*/
! 		if (vacuum_type == VACUUM_ANALYZE)
  		{
! 			sprintf(query, "update pg_autovacuum set cnt_at_last_analyze = n_tup_ins + n_tup_upd, cnt_at_last_vacuum = n_tup_upd + n_tup_del from pg_stat_all_tables where table_oid = relid and relid = %u", table_oid);
! 			send_query(query, dbi);
  		}
+ 		/* 
+ 			* update only the analyze thresholds  if
+ 			* we only did an analyze
+ 			*/
+ 		else
+ 		{
+ 			sprintf(query, "update pg_autovacuum set cnt_at_last_analyze = n_tup_ins + n_tup_upd, from pg_stat_all_tables where table_oid = relid and relid = %u", table_oid);
+ 			send_query(query, dbi);
+ 		}
+ 			
+ 		// FIXME: Need to think about this and pg_stat roll over issues
+ //		/*
+ //		 * 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_pg_autovacuum_table(db_info *dbi)
  {
+ 	/*
+ 	 * This function will update the pg_autovacuum system table in two steps:
+ 	 * 1) Delete entries that are no longer in pg_class an
+ 	 * 2) Add zero'd out entries to the pg_autovacuum table for new tables that exist in pg_class not in pg_autovacuum
+ 	 */
+ 	 
  	int			disconnect = 0;
! 	char		query[4096];
  
  	if (dbi->conn == NULL)
  	{
***************
*** 219,387 ****
  
  	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);
! 					}
! 				}
! 			}						/* 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 from list.", tbl->table_name);
- 		log_entry(logbuffer);
- 		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);
- 	sprintf(logbuffer, "     relid: %u;   relisshared: %i", tbl->relid, tbl->relisshared);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "     reltuples: %f;  relpages: %u", tbl->reltuples, tbl->relpages);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "     curr_analyze_count: %li; curr_vacuum_count: %li",
- 			tbl->curr_analyze_count, tbl->curr_vacuum_count);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "     last_analyze_count: %li; last_vacuum_count: %li",
- 			tbl->CountAtLastAnalyze, tbl->CountAtLastVacuum);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "     analyze_threshold: %li; vacuum_threshold: %li",
- 			tbl->analyze_threshold, tbl->vacuum_threshold);
- 	log_entry(logbuffer);
- 	fflush(LOGOUTPUT);
- }
  
  /* End of table Management Functions */
  
--- 280,301 ----
  
  	if (dbi->conn != NULL)
  	{
+ 		/* 
+ 		 * Delete entries in pg_autovacuum that are no longer in pg_class 
+ 		 */
+ 		send_query("DELETE from pg_autovacuum where table_oid not in (select relid from pg_stat_all_tables )",dbi);
+ 		
  		/*
! 		 * Insert entires into pg_autovacuum for new tables (ones that exist in pg_class / pg_stat.., but not in pg_autovacuum) 
! 		 * and fill in defaut values for these new tables.
! 		 * then add them to the table list.
  		 */
! 		sprintf(query, "insert into pg_autovacuum (table_oid, analyze_base_threshold, vacuum_base_threshold, analyze_scaling_factor, vacuum_scaling_factor, analyze_threshold, vacuum_threshold, cnt_at_last_analyze, cnt_at_last_vacuum)   select a.oid, %i, %i, %f, %f, -1, -1, 0, 0 from pg_class a inner join pg_stat_all_tables b on a.oid=b.relid left outer join pg_autovacuum c on a.oid = c.table_oid where a.relkind = 'r' and schemaname not like 'pg_temp_%%' and a.oid not in (select distinct table_oid from pg_autovacuum)",args->analyze_base_threshold, args->vacuum_base_threshold, args->analyze_scaling_factor, args->vacuum_scaling_factor ); 
! 		elog(DEBUG5, query);
! 		send_query(query,dbi);
  	}
  }
  
  
  /* End of table Management Functions */
  
***************
*** 398,405 ****
  	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.");
! 		fflush(LOGOUTPUT);
  		return NULL;
  	}
  
--- 312,318 ----
  	DLAddHead(db_list, DLNewElem(init_dbinfo((char *) "template1", 0, 0)));
  	if (DLGetHead(db_list) == NULL)
  	{							/* Make sure init_dbinfo was successful */
! 		elog(ERROR, logbuffer);
  		return NULL;
  	}
  
***************
*** 419,427 ****
  			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;
--- 332,337 ----
***************
*** 457,465 ****
  	newdbinfo->table_list = DLNewList();
  	newdbinfo->conn = NULL;
  
- 	if (args->debug >= 2)
- 		print_table_list(newdbinfo->table_list);
- 
  	return newdbinfo;
  }
  
--- 367,372 ----
***************
*** 476,486 ****
  				t = 0,
  				found_match = 0;
  
! 	if (args->debug >= 2)
! 	{
! 		log_entry("updating the database list");
! 		fflush(LOGOUTPUT);
! 	}
  
  	if (dbi_template1->conn == NULL)
  	{
--- 383,389 ----
  				t = 0,
  				found_match = 0;
  
! 	elog(DEBUG2, "pg_autovacuum: updating the database list");
  
  	if (dbi_template1->conn == NULL)
  	{
***************
*** 565,577 ****
  						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);
  					}
  				}
! 			}						/* end of for loop that adds tables */
  		}
- 		fflush(LOGOUTPUT);
  		PQclear(res);
  		res = NULL;
  		if (args->debug >= 3)
--- 468,479 ----
  						atol(PQgetvalue(res, i, PQfnumber(res, "age"))))));
  					if (args->debug >= 1)
  					{
! 						sprintf(logbuffer, "pg_autovacuum: added database %s", ((db_info *) DLE_VAL(DLGetTail(db_list)))->dbname);
! 						elog(DEBUG1, logbuffer);
  					}
  				}
! 			}	/* end of for loop that adds tables */
  		}
  		PQclear(res);
  		res = NULL;
  		if (args->debug >= 3)
***************
*** 625,636 ****
  {
  	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);
! 		fflush(LOGOUTPUT);
! 	}
  	DLRemove(db_to_remove);
  	if (dbi->conn)
  		db_disconnect(dbi);
--- 527,535 ----
  {
  	db_info    *dbi = ((db_info *) DLE_VAL(db_to_remove));
  
! 	sprintf(logbuffer, "pg_autovacuum: Removing db: %s from list.", dbi->dbname);
! 	elog(DEBUG1, logbuffer);
! 	
  	DLRemove(db_to_remove);
  	if (dbi->conn)
  		db_disconnect(dbi);
***************
*** 651,657 ****
  	}
  	if (dbi->table_list)
  	{
- 		free_tbl_list(dbi->table_list);
  		dbi->table_list = NULL;
  	}
  	if (dbi)
--- 550,555 ----
***************
*** 696,726 ****
  print_db_info(db_info * dbi, int print_tbl_list)
  {
  	sprintf(logbuffer, "dbname: %s", (dbi->dbname) ? dbi->dbname : "(null)");
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  oid: %u", dbi->oid);
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  username: %s", (dbi->username) ? dbi->username : "(null)");
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  password: %s", (dbi->password) ? dbi->password : "(null)");
! 	log_entry(logbuffer);
  	
  	if (dbi->conn != NULL)
! 		log_entry("  conn is valid, (connected)");
  	else
! 		log_entry("  conn is null, (not connected)");
  
  	sprintf(logbuffer, "  default_analyze_threshold: %li", dbi->analyze_threshold);
! 	log_entry(logbuffer);
  	
  	sprintf(logbuffer, "  default_vacuum_threshold: %li", dbi->vacuum_threshold);
! 	log_entry(logbuffer);
! 	
! 	fflush(LOGOUTPUT);
! 	if (print_tbl_list > 0)
! 		print_table_list(dbi->table_list);
  }
  
  /* End of DB List Management Function */
--- 594,620 ----
  print_db_info(db_info * dbi, int print_tbl_list)
  {
  	sprintf(logbuffer, "dbname: %s", (dbi->dbname) ? dbi->dbname : "(null)");
! 	elog(DEBUG2, logbuffer);
  	
  	sprintf(logbuffer, "  oid: %u", dbi->oid);
! 	elog(DEBUG2, logbuffer);
  	
  	sprintf(logbuffer, "  username: %s", (dbi->username) ? dbi->username : "(null)");
! 	elog(DEBUG2, logbuffer);
  	
  	sprintf(logbuffer, "  password: %s", (dbi->password) ? dbi->password : "(null)");
! 	elog(DEBUG2, logbuffer);
  	
  	if (dbi->conn != NULL)
! 		elog(DEBUG2, "  conn is valid, (connected)");
  	else
! 		elog(DEBUG2, "  conn is null, (not connected)");
  
  	sprintf(logbuffer, "  default_analyze_threshold: %li", dbi->analyze_threshold);
! 	elog(DEBUG2, logbuffer);
  	
  	sprintf(logbuffer, "  default_vacuum_threshold: %li", dbi->vacuum_threshold);
! 	elog(DEBUG2, logbuffer);
  }
  
  /* End of DB List Management Function */
***************
*** 739,746 ****
  	{
  		sprintf(logbuffer, "Failed connection to database %s with error: %s.",
  				dbi->dbname, PQerrorMessage(db_conn));
! 		log_entry(logbuffer);
! 		fflush(LOGOUTPUT);
  		PQfinish(db_conn);
  		db_conn = NULL;
  	}
--- 633,639 ----
  	{
  		sprintf(logbuffer, "Failed connection to database %s with error: %s.",
  				dbi->dbname, PQerrorMessage(db_conn));
! 		elog(LOG, logbuffer);
  		PQfinish(db_conn);
  		db_conn = NULL;
  	}
***************
*** 780,799 ****
  	if (dbi->conn == NULL)
  		return NULL;
  
! 	if (args->debug >= 4)
! 		log_entry(query);
  
  	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);
  		sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
! 		log_entry(logbuffer);
! 		fflush(LOGOUTPUT);
  		return NULL;
  	}
  	if (PQresultStatus(res) != PGRES_TUPLES_OK &&
--- 673,690 ----
  	if (dbi->conn == NULL)
  		return NULL;
  
! 	elog(DEBUG5, query);
  
  	res = PQexec(dbi->conn, query);
  
  	if (!res)
  	{
  		sprintf(logbuffer,
! 		   "pg_autovacuum: Fatal error occured while sending query (%s) to database %s",
  				query, dbi->dbname);
! 		elog(ERROR, logbuffer);
  		sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
! 		elog(ERROR, logbuffer);
  		return NULL;
  	}
  	if (PQresultStatus(res) != PGRES_TUPLES_OK &&
***************
*** 802,811 ****
  		sprintf(logbuffer,
  		  "Can not refresh statistics information from the database %s.",
  				dbi->dbname);
! 		log_entry(logbuffer);
  		sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
! 		log_entry(logbuffer);
! 		fflush(LOGOUTPUT);
  		PQclear(res);
  		return NULL;
  	}
--- 693,701 ----
  		sprintf(logbuffer,
  		  "Can not refresh statistics information from the database %s.",
  				dbi->dbname);
! 		elog(ERROR, logbuffer);
  		sprintf(logbuffer, "The error is [%s]", PQresultErrorMessage(res));
! 		elog(ERROR, logbuffer);
  		PQclear(res);
  		return NULL;
  	}
***************
*** 829,835 ****
  static cmd_args *
  get_cmd_args(int argc, char *argv[])
  {
! 	int			c;
  
  	args = (cmd_args *) malloc(sizeof(cmd_args));
  	args->sleep_base_value = SLEEPBASEVALUE;
--- 719,725 ----
  static cmd_args *
  get_cmd_args(int argc, char *argv[])
  {
! //	int			c;
  
  	args = (cmd_args *) malloc(sizeof(cmd_args));
  	args->sleep_base_value = SLEEPBASEVALUE;
***************
*** 839,845 ****
  	args->analyze_base_threshold = -1;
  	args->analyze_scaling_factor = -1;
  	args->debug = AUTOVACUUM_DEBUG;
- 	args->daemonize = 0;
  	args->user = 0;
  	args->password = 0;
  	args->host = 0;
--- 729,734 ----
***************
*** 850,856 ****
  	 * Fixme: Should add some sanity checking such as positive integer
  	 * values etc
  	 */
! 	while ((c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD")) != -1)
  	{
  		switch (c)
  		{
--- 739,745 ----
  	 * Fixme: Should add some sanity checking such as positive integer
  	 * values etc
  	 */
! /*	while ((c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD")) != -1)
  	{
  		switch (c)
  		{
***************
*** 872,880 ****
  			case 'A':
  				args->analyze_scaling_factor = atof(optarg);
  				break;
- 			case 'D':
- 				args->daemonize++;
- 				break;
  			case 'd':
  				args->debug = atoi(optarg);
  				break;
--- 761,766 ----
***************
*** 897,999 ****
  				usage();
  				exit(0);
  			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()
- {
- 	int			i = 0;
- 	float		f = 0;
- 
- 	fprintf(stderr, "usage: pg_autovacuum \n");
- 	fprintf(stderr, "   [-D] Daemonize (Detach from tty and run in the background)\n");
- 	i = AUTOVACUUM_DEBUG;
- 	fprintf(stderr, "   [-d] debug (debug level=0,1,2,3; default=%i)\n", i);
- 
- 	i = SLEEPBASEVALUE;
- 	fprintf(stderr, "   [-s] sleep base value (default=%i)\n", i);
- 	f = SLEEPSCALINGFACTOR;
- 	fprintf(stderr, "   [-S] sleep scaling factor (default=%f)\n", f);
- 
- 	i = VACBASETHRESHOLD;
- 	fprintf(stderr, "   [-v] vacuum base threshold (default=%i)\n", i);
- 	f = VACSCALINGFACTOR;
- 	fprintf(stderr, "   [-V] vacuum scaling factor (default=%f)\n", f);
- 	i = i / 2;
- 	fprintf(stderr, "   [-a] analyze base threshold (default=%i)\n", i);
- 	f = f / 2;
- 	fprintf(stderr, "   [-A] analyze scaling factor (default=%f)\n", f);
- 
- 	fprintf(stderr, "   [-L] logfile (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()
- {
- 	sprintf(logbuffer, "Printing command_args");
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->host=%s", (args->host) ? args->host : "(null)");
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->port=%s", (args->port) ? args->port : "(null)");
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->username=%s", (args->user) ? args->user : "(null)");
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->password=%s", (args->password) ? args->password : "(null)");
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->logfile=%s", (args->logfile) ? args->logfile : "(null)");
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->daemonize=%i", args->daemonize);
- 	log_entry(logbuffer);
- 
- 	sprintf(logbuffer, "  args->sleep_base_value=%i", args->sleep_base_value);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->sleep_scaling_factor=%f", args->sleep_scaling_factor);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->vacuum_base_threshold=%i", args->vacuum_base_threshold);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->vacuum_scaling_factor=%f", args->vacuum_scaling_factor);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->analyze_base_threshold=%i", args->analyze_base_threshold);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->analyze_scaling_factor=%f", args->analyze_scaling_factor);
- 	log_entry(logbuffer);
- 	sprintf(logbuffer, "  args->debug=%i", args->debug);
- 	log_entry(logbuffer);
- 
- 	fflush(LOGOUTPUT);
- }
  
  /* Beginning of AutoVacuum Main Program */
! int
! main(int argc, char *argv[])
  {
  	char		buf[256];
  	int			j = 0,
--- 783,814 ----
  				usage();
  				exit(0);
  			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;
  }
  
  
  /* Beginning of AutoVacuum Main Program */
! void AutoVacLoop(void)
  {
  	char		buf[256];
  	int			j = 0,
***************
*** 1011,1048 ****
  	struct timeval now,
  				then;
  
! 	args = get_cmd_args(argc, argv);	/* Get Command Line Args and put
  										 * them in the args struct */
  
- 	/* Dameonize if requested */
- 	if (args->daemonize == 1)
- 		daemonize();
- 
- 	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();
- 
  	/* 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("Error: GUC variable stats_row_level must be enabled.");
! 		log_entry("       Please fix the problems and try again.");
! 		fflush(LOGOUTPUT);
! 
  		exit(1);
  	}
  
--- 826,845 ----
  	struct timeval now,
  				then;
  
! //  Fixme: the args stuct needs to be reimplemented since we are no longer a command line app.
! //	args = get_cmd_args(argc, argv);	/* Get Command Line Args and put
! 	args = get_cmd_args(0, NULL);	/* Get Command Line Args and put
  										 * them in the args struct */
  
  	/* Init the db list with template1 */
  	db_list = init_db_list();
  	if (db_list == NULL)
! 		exit(1);
  	
  	if (check_stats_enabled(((db_info *) DLE_VAL(DLGetHead(db_list)))) != 0)
  	{
! 		elog(ERROR, "pg_autovacuum: GUC variable stats_row_level must be enabled.");
! 		elog(ERROR, "       Please fix the problems and try again.");
  		exit(1);
  	}
  
***************
*** 1050,1055 ****
--- 847,873 ----
  
  	while (1)
  	{							/* Main Loop */
+ 
+ 		/*
+ 		 * Emergency bailout if postmaster has died.  This is to avoid the
+ 		 * necessity for manual cleanup of all postmaster children.
+ 		 */
+ 		if (!PostmasterIsAlive(true))
+ 			exit(1);
+ 
+ 		if (got_SIGHUP)
+ 		{
+ 			got_SIGHUP = false;
+ 			ProcessConfigFile(PGC_SIGHUP);
+ 		}
+ 		if (shutdown_requested)
+ 		{
+ 			ShutdownXLOG(0, 0);
+ 			DumpFreeSpaceMap(0, 0);
+ 			/* Normal exit from the bgwriter is here */
+ 			proc_exit(0);		/* done */
+ 		}
+ 
  		db_elem = DLGetHead(db_list);	/* Reset cur_db_node to the
  										 * beginning of the db_list */
  
***************
*** 1061,1069 ****
  			if (dbs->conn == NULL)
  			{					/* Serious problem: We can't connect to
  								 * template1 */
! 				log_entry("Error: Cannot connect to template1, exiting.");
! 				fflush(LOGOUTPUT);
! 				fclose(LOGOUTPUT);
  				exit(1);
  			}
  		}
--- 879,885 ----
  			if (dbs->conn == NULL)
  			{					/* Serious problem: We can't connect to
  								 * template1 */
! 				elog(ERROR, "pg_autovacuum: Cannot connect to template1, exiting.");
  				exit(1);
  			}
  		}
***************
*** 1072,1095 ****
  												 * 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 % 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 */
--- 888,915 ----
  												 * time */
  			update_db_list(db_list);	/* Add and remove databases from
  										 * the list */
! 		
! 		/* Loop through databases in list */
  		while (db_elem != NULL)
! 		{
  			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 (xid_wraparound_check(dbs) == 0)
  				{
+ 					long curr_vacuum_count, curr_analyze_count;
+ 					long cnt_at_last_vacuum, cnt_at_last_analyze;
+ 					float vacuum_threshold, analyze_threshold;
+ 					char table_name[512];
+ 					
+ 					if (loops % UPDATE_INTERVAL == 0)	
+ 						update_pg_autovacuum_table(dbs); 
+ 						
  					res = send_query(TABLE_STATS_QUERY, dbs);	/* Get an updated
  																 * snapshot of this dbs
  																 * table stats */
***************
*** 1097,1174 ****
  					{
  						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)
! 									{
! 										/*
! 										* if relisshared = t and database !=
! 										* template1 then only do an analyze
! 										*/
! 										if (tbl->relisshared > 0 && strcmp("template1", dbs->dbname))
! 											snprintf(buf, sizeof(buf), "ANALYZE %s", tbl->table_name);
! 										else
! 											snprintf(buf, sizeof(buf), "VACUUM ANALYZE %s", tbl->table_name);
! 										if (args->debug >= 1)
! 										{
! 											sprintf(logbuffer, "Performing: %s", buf);
! 											log_entry(logbuffer);
! 											fflush(LOGOUTPUT);
! 										}
! 										send_query(buf, dbs);
! 										update_table_thresholds(dbs, tbl, VACUUM_ANALYZE);
! 										if (args->debug >= 2)
! 											print_table_info(tbl);
! 									}
! 									else if (tbl->curr_analyze_count - tbl->CountAtLastAnalyze >= tbl->analyze_threshold)
! 									{
! 										snprintf(buf, sizeof(buf), "ANALYZE %s", tbl->table_name);
! 										if (args->debug >= 1)
! 										{
! 											sprintf(logbuffer, "Performing: %s", buf);
! 											log_entry(logbuffer);
! 											fflush(LOGOUTPUT);
! 										}
! 										send_query(buf, dbs);
! 										update_table_thresholds(dbs, tbl, ANALYZE_ONLY);
! 										if (args->debug >= 2)
! 											print_table_info(tbl);
! 									}
! 									
! 									break;	/* once we have found a match, no
! 											* need to keep checking. */
! 								}
! 								
  								/*
! 								* 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()) */
--- 917,975 ----
  					{
  						for (j = 0; j < PQntuples(res); j++)
  						{			/* loop through result set */
! 							/*
! 							* Check to see if we need to
! 							* vacuum analyze, or just analyze
! 							* if needed, do so, then update table thresholds and
! 							* related information
! 							*/
! 							curr_vacuum_count = (atol(PQgetvalue(res, j, PQfnumber(res, "curr_vacuum_count"))));
! 							curr_analyze_count = (atol(PQgetvalue(res, j, PQfnumber(res, "curr_analyze_count"))));
! 							cnt_at_last_vacuum = (atol(PQgetvalue(res, j, PQfnumber(res, "cnt_at_last_vacuum"))));
! 							cnt_at_last_analyze = (atol(PQgetvalue(res, j, PQfnumber(res, "cnt_at_last_analyze"))));
! 							vacuum_threshold = (atof(PQgetvalue(res, j, PQfnumber(res, "vacuum_threshold"))));
! 							analyze_threshold = (atof(PQgetvalue(res, j, PQfnumber(res, "analyze_threshold"))));
! 							strcpy(table_name,"\"");
! 							strcat(table_name, PQgetvalue(res,j, PQfnumber(res, "schemaname")));
! 							strcat(table_name,"\".\"");
! 							strcat(table_name, PQgetvalue(res,j, PQfnumber(res, "relname")));
! 							strcat(table_name,"\"");
! 							
! 							/* FIXME: Remove this debug if block before submitting the patch */
! /*							if(strcmp("foo",PQgetvalue(res,j, PQfnumber(res, "relname"))) == 0 )
! 							{
! 								snprintf(buf, sizeof(buf), "relname = %s \ncurr_vacuum_count = %li; curr_analyze_count = %li\ncnt_at_last_vacuum = %li ;cnt_at_last_analyze = %li\nvacuum_threshold = %f ;analyze_threshold = %f", table_name, curr_vacuum_count, curr_analyze_count, cnt_at_last_vacuum, cnt_at_last_analyze, vacuum_threshold, analyze_threshold);
! 								elog(DEBUG2, buf);
! 							} */
! 							if ((curr_vacuum_count - cnt_at_last_vacuum) >= vacuum_threshold)
! 							{
! 								elog(DEBUG2, "pg_autovacuum: about to do a vacuum.");
  								/*
! 								* if relisshared = t and database !=
! 								* template1 then only do an analyze
  								*/
! 								//elog(DEBUG2, PQgetvalue(res,j, PQfnumber(res, "relisshared")));
! 								if ((strcmp("t",PQgetvalue(res,j, PQfnumber(res, "relisshared"))) == 0 ) && (strcmp(dbs->dbname,"template1") == 0 ))
! 									snprintf(buf, sizeof(buf), "ANALYZE %s", table_name);
! 								else
! 									snprintf(buf, sizeof(buf), "VACUUM ANALYZE %s", table_name);
! 								
! 								sprintf(logbuffer, "pg_autovacuum: Performing: %s", buf);
! 								elog(DEBUG1, logbuffer);
  								
! 								send_query(buf, dbs);
! 								update_table_thresholds(dbs, atooid(PQgetvalue(res, j, PQfnumber(res, "oid"))), VACUUM_ANALYZE);
! 							}
! 							else if (curr_analyze_count - cnt_at_last_analyze >= analyze_threshold)
! 							{
! 								snprintf(buf, sizeof(buf), "ANALYZE %s", table_name);
! 								
! 								sprintf(logbuffer, "pg_autovacuum: Performing: %s", buf);
! 								elog(DEBUG1, logbuffer);
! 								
! 								send_query(buf, dbs);
! 								update_table_thresholds(dbs, atooid(PQgetvalue(res, j, PQfnumber(res, "oid"))), ANALYZE_ONLY);
! 							}
  						}			/* end for j loop (tuples in PGresult) */
  					}			/* end if (res != NULL) */
  				}				/* close of if(xid_wraparound_check()) */
***************
*** 1179,1206 ****
  			}
  			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,
! 			 "%i All DBs checked in: %.0f usec, will sleep for %i secs.",
! 					loops, diff, sleep_secs);
! 			log_entry(logbuffer);
! 			fflush(LOGOUTPUT);
! 		}
! 
! 		sleep(sleep_secs);		/* Larger Pause between outer loops */
! 
  		gettimeofday(&then, 0); /* Reset time counter */
! 
! 	}							/* end of while loop */
  
  	/*
  	 * program is exiting, this should never run, but is here to make
--- 980,1006 ----
  			}
  			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++;
! 			
! 		sprintf(logbuffer,
! 			"pg_autovacuum: loop %i; All DBs checked in: %.0f usec, will sleep for %i secs.",
! 				loops, diff, sleep_secs);
! 		elog(DEBUG2, logbuffer);
! 		
! 		/* Larger Pause between outer loops */
! 		if (!(got_SIGHUP || shutdown_requested))
! 			pg_usleep((long)(sleep_secs * 1000000L));
! 		
  		gettimeofday(&then, 0); /* Reset time counter */
! 		
! 	}	/* end of while loop */
  
  	/*
  	 * program is exiting, this should never run, but is here to make
***************
*** 1208,1212 ****
  	 */
  	free_db_list(db_list);
  	free_cmd_args();
! 	return EXIT_SUCCESS;
  }
--- 1008,1012 ----
  	 */
  	free_db_list(db_list);
  	free_cmd_args();
! 	exit(0);
  }
*** ./src/backend/postmaster/postmaster.c.orig	2004-06-16 01:54:26.540427813 -0400
--- ./src/backend/postmaster/postmaster.c	2004-06-16 01:28:41.369792465 -0400
***************
*** 192,197 ****
--- 192,198 ----
  /* PIDs of special child processes; 0 when not running */
  static pid_t StartupPID = 0,
  			BgWriterPID = 0,
+ 			AutoVacPID = 0,
  			PgStatPID = 0;
  
  /* Startup/shutdown state */
***************
*** 294,299 ****
--- 295,301 ----
  
  #define StartupDataBase()		StartChildProcess(BS_XLOG_STARTUP)
  #define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
+ #define StartAutoVac() StartChildProcess(BS_XLOG_AUTOVAC)
  
  
  /*
***************
*** 781,787 ****
  	 *
  	 * CAUTION: when changing this list, check for side-effects on the signal
  	 * handling setup of child processes.  See tcop/postgres.c,
! 	 * bootstrap/bootstrap.c, postmaster/bgwriter.c, and postmaster/pgstat.c.
  	 */
  	pqinitmask();
  	PG_SETMASK(&BlockSig);
--- 783,790 ----
  	 *
  	 * CAUTION: when changing this list, check for side-effects on the signal
  	 * handling setup of child processes.  See tcop/postgres.c,
! 	 * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/pgstat.c,
! 	 * and postmaster/pg_autovacuum.c.
  	 */
  	pqinitmask();
  	PG_SETMASK(&BlockSig);
***************
*** 1148,1153 ****
--- 1151,1171 ----
  				kill(BgWriterPID, SIGUSR2);
  		}
  
+ 		/*
+ 		 * If no AutoVacuum process is running, and we are not in
+ 		 * a state that prevents it, start one.  It doesn't matter if this
+ 		 * fails, we'll just try again later.
+ 		 */
+ 		if (autovac_start_daemon)
+ 		{
+ 			if (AutoVacPID == 0 && StartupPID == 0 && !FatalError)
+ 			{
+ 				AutoVacPID = StartAutoVac();
+ 				/* If shutdown is pending, set it going */
+ 				if (Shutdown > NoShutdown && AutoVacPID != 0)
+ 					kill(AutoVacPID, SIGUSR2);
+ 			}
+ 		}	
  		/* If we have lost the stats collector, try to start a new one */
  		if (PgStatPID == 0 &&
  			StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
***************
*** 1510,1515 ****
--- 1528,1548 ----
  	backendPID = (int) ntohl(canc->backendPID);
  	cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
  
+ 	if (backendPID == BgWriterPID)
+ 	{
+ 		ereport(DEBUG2,
+ 				(errmsg_internal("ignoring cancel request for bgwriter process %d",
+ 								 backendPID)));
+ 		return;
+ 	}
+ 	if (backendPID == AutoVacPID)
+ 	{
+ 		ereport(DEBUG2,
+ 				(errmsg_internal("ignoring cancel request for autovacuum process %d",
+ 								 backendPID)));
+ 		return;
+ 	}
+ 
  	/*
  	 * See if we have a matching backend.  In the EXEC_BACKEND case, we
  	 * can no longer access the postmaster's own backend list, and must
***************
*** 1691,1696 ****
--- 1724,1731 ----
  		SignalChildren(SIGHUP);
  		if (BgWriterPID != 0)
  			kill(BgWriterPID, SIGHUP);
+ 		if (AutoVacPID != 0)
+ 			kill(AutoVacPID, SIGHUP);
  		/* PgStatPID does not currently need SIGHUP */
  		load_hba();
  		load_ident();
***************
*** 1749,1754 ****
--- 1784,1793 ----
  			/* And tell it to shut down */
  			if (BgWriterPID != 0)
  				kill(BgWriterPID, SIGUSR2);
+ 			/* I don't think we need to Start the autovac process if not running */
+ 			/* And tell it to shut down */
+ 			if (AutoVacPID != 0)
+ 				kill(AutoVacPID, SIGUSR2);
  			/* Tell pgstat to shut down too; nothing left for it to do */
  			if (PgStatPID != 0)
  				kill(PgStatPID, SIGQUIT);
***************
*** 1793,1798 ****
--- 1832,1840 ----
  			/* And tell it to shut down */
  			if (BgWriterPID != 0)
  				kill(BgWriterPID, SIGUSR2);
+ 			/* And tell it to shut down */
+ 			if (AutoVacPID != 0)
+ 				kill(AutoVacPID, SIGUSR2);
  			/* Tell pgstat to shut down too; nothing left for it to do */
  			if (PgStatPID != 0)
  				kill(PgStatPID, SIGQUIT);
***************
*** 1811,1816 ****
--- 1853,1860 ----
  				kill(StartupPID, SIGQUIT);
  			if (BgWriterPID != 0)
  				kill(BgWriterPID, SIGQUIT);
+ 			if (AutoVacPID != 0)
+ 				kill(AutoVacPID, SIGQUIT);
  			if (PgStatPID != 0)
  				kill(PgStatPID, SIGQUIT);
  			if (DLGetHead(BackendList))
***************
*** 1905,1910 ****
--- 1949,1968 ----
  			else if (PgStatPID == 0 && Shutdown == NoShutdown)
  				PgStatPID = pgstat_start();
  
+ 			/*
+ 			 * Crank up the AutoVac.  It doesn't matter if this
+ 			 * fails, we'll just try again later.
+ 			 */
+ 			Assert(AutoVacPID == 0);
+ 			if(autovac_start_daemon)
+ 				AutoVacPID = StartAutoVac();
+ 			
+ 			/*
+ 			 * Go to shutdown mode if a shutdown request was pending.
+ 			 */
+ 			if (Shutdown > NoShutdown && AutoVacPID != 0)
+ 				kill(AutoVacPID, SIGUSR2);
+ 			
  			continue;
  		}
  
***************
*** 1963,1969 ****
  		 * Wait for all children exit, then reset shmem and
  		 * StartupDataBase.
  		 */
! 		if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0)
  			goto reaper_done;
  		ereport(LOG,
  			(errmsg("all server processes terminated; reinitializing")));
--- 2021,2027 ----
  		 * Wait for all children exit, then reset shmem and
  		 * StartupDataBase.
  		 */
! 		if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0 || AutoVacPID != 0)
  			goto reaper_done;
  		ereport(LOG,
  			(errmsg("all server processes terminated; reinitializing")));
***************
*** 1986,1991 ****
--- 2044,2052 ----
  		/* And tell it to shut down */
  		if (BgWriterPID != 0)
  			kill(BgWriterPID, SIGUSR2);
+ 		/* Tell AutoVac to shut down */
+ 		if (AutoVacPID != 0)
+ 			kill(AutoVacPID, SIGUSR2);
  	}
  
  reaper_done:
***************
*** 2134,2139 ****
--- 2195,2214 ----
  	}
  
  	FatalError = true;
+ 
+ 	/* Take care of the autovac too */
+ 	if (pid == AutoVacPID)
+ 		AutoVacPID = 0;
+ 	else if (AutoVacPID != 0 && !FatalError)
+ 	{
+ 		ereport(DEBUG2,
+ 				(errmsg_internal("sending %s to process %d",
+ 								 (SendStop ? "SIGSTOP" : "SIGQUIT"),
+ 								 (int) AutoVacPID)));
+ 		kill(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
+ 	}
+ 
+ 	FatalError = true;
  }
  
  /*
***************
*** 3098,3103 ****
--- 3173,3182 ----
  				ereport(LOG,
  						(errmsg("could not fork background writer process: %m")));
  				break;
+ 			case BS_XLOG_AUTOVAC:
+ 				ereport(LOG,
+ 						(errmsg("could not fork auto vacuum process: %m")));
+ 				break;
  			default:
  				ereport(LOG,
  						(errmsg("could not fork process: %m")));
*** ./src/backend/utils/misc/guc.c.orig	2004-06-16 01:38:09.262543064 -0400
--- ./src/backend/utils/misc/guc.c	2004-06-16 01:22:07.494964353 -0400
***************
*** 45,50 ****
--- 45,51 ----
  #include "parser/parse_expr.h"
  #include "parser/parse_relation.h"
  #include "postmaster/bgwriter.h"
+ #include "postmaster/pg_autovacuum.h"
  #include "postmaster/postmaster.h"
  #include "storage/bufmgr.h"
  #include "storage/fd.h"
***************
*** 627,632 ****
--- 628,642 ----
  		true, NULL, NULL
  	},
  	{
+ 		{"auto_vacuum_enabled", PGC_POSTMASTER, AUTOVACUUM,
+ 			gettext_noop("Starts the auto vacuum subprocess."),
+ 			NULL
+ 		},
+ 		&autovac_start_daemon,
+ 		true, NULL, NULL
+ 	 
+ 	},
+ 	{
  		{"stats_start_collector", PGC_POSTMASTER, STATS_COLLECTOR,
  			gettext_noop("Starts the server statistics-collection subprocess."),
  			NULL
*** ./src/backend/utils/misc/postgresql.conf.sample.orig	2004-06-16 01:39:06.116310842 -0400
--- ./src/backend/utils/misc/postgresql.conf.sample	2004-06-08 00:05:43.000000000 -0400
***************
*** 218,223 ****
--- 218,230 ----
  
  
  #---------------------------------------------------------------------------
+ # VACUUM DAEMON
+ #---------------------------------------------------------------------------
+ 
+ #auto_vacuum_enabled = true
+ 
+ 
+ #---------------------------------------------------------------------------
  # CLIENT CONNECTION DEFAULTS
  #---------------------------------------------------------------------------
  
*** ./src/include/bootstrap/bootstrap.h.orig	2004-06-05 15:07:32.000000000 -0400
--- ./src/include/bootstrap/bootstrap.h	2004-06-05 15:07:04.000000000 -0400
***************
*** 59,63 ****
--- 59,64 ----
  #define BS_XLOG_BOOTSTRAP	1
  #define BS_XLOG_STARTUP		2
  #define BS_XLOG_BGWRITER	3
+ #define BS_XLOG_AUTOVAC		4
  
  #endif   /* BOOTSTRAP_H */
*** ./src/include/postmaster/pg_autovacuum.h.orig	2004-06-07 00:40:16.000000000 -0400
--- ./src/include/postmaster/pg_autovacuum.h	2004-06-16 00:02:59.000000000 -0400
***************
*** 3,42 ****
   * (c) 2003 Matthew T. O'Connor
   */
  
  #include "postgres_fe.h"
  
  #include <unistd.h>
- #ifdef HAVE_GETOPT_H
- #include <getopt.h>
- #endif
  #include <time.h>
  #include <sys/time.h>
  
! /* These next two lines are correct when pg_autovaccum is compiled
!    from within the postgresql source tree  */
! #include "libpq-fe.h"
  #include "lib/dllist.h"
- /* Had to change the last two lines to compile on
-    Redhat outside of postgresql source tree */
- /*
- #include "/usr/include/libpq-fe.h"
- #include "/usr/include/pgsql/server/lib/dllist.h"
- */
  
  #define AUTOVACUUM_DEBUG	1
  #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' and schemaname not like 'pg_temp_%'"
  
- #define FRONTEND
  #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'"
--- 3,36 ----
   * (c) 2003 Matthew T. O'Connor
   */
  
+ #ifndef _AUTOVAC_H
+ #define _AUTOVAC_H
+ 
+ #define FRONTEND
  #include "postgres_fe.h"
  
  #include <unistd.h>
  #include <time.h>
  #include <sys/time.h>
  
! #include "../../interfaces/libpq/libpq-fe.h"
  #include "lib/dllist.h"
  
+ /* default settings defined here */
  #define AUTOVACUUM_DEBUG	1
  #define VACBASETHRESHOLD	1000
  #define VACSCALINGFACTOR	2
! #define SLEEPBASEVALUE		15
  #define SLEEPSCALINGFACTOR	2
! #define UPDATE_INTERVAL		1
  
  /* these two constants are used to tell update_table_stats what operation we just perfomred */
  #define VACUUM_ANALYZE		0
  #define ANALYZE_ONLY		1
  
! /* define the main queries */
! #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, c.cnt_at_last_analyze, c.cnt_at_last_vacuum, b.n_tup_ins + b.n_tup_upd as curr_analyze_count, b.n_tup_upd + b.n_tup_del as curr_vacuum_count, case when vacuum_threshold < 0 then c.vacuum_base_threshold + c.vacuum_scaling_factor * a.reltuples else c.vacuum_threshold end as vacuum_threshold, case when analyze_threshold < 0 then c.analyze_base_threshold + c.analyze_scaling_factor * a.reltuples else c.analyze_threshold end as analyze_threshold from pg_class a inner join pg_stat_all_tables b on a.oid=b.relid left outer join pg_autovacuum c on a.oid = c.table_oid where a.relkind = 'r' and schemaname not like 'pg_temp_%' and c.table_oid is not null"
  
  #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'"
***************
*** 44,49 ****
--- 38,50 ----
  /* define atooid */
  #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
  
+ 
+ /* ----------
+  * GUC parameters
+  * ----------
+  */
+ extern bool autovac_start_daemon; 
+ 
  /* define cmd_args stucture */
  struct cmdargs
  {
***************
*** 72,79 ****
  {
  	Oid			oid;
  	long		age;
! 	long		analyze_threshold,
! 				vacuum_threshold;		/* Use these as defaults for table
  										 * thresholds */
  	PGconn	   *conn;
  	char	   *dbname,
--- 73,82 ----
  {
  	Oid			oid;
  	long		age;
! 	long		analyze_threshold, 
! 				vacuum_threshold;		
! 									/* FIXME: needs to be changed to both base and scaling factor */
! 									/* Use these as defaults for table
  										 * thresholds */
  	PGconn	   *conn;
  	char	   *dbname,
***************
*** 107,116 ****
  typedef struct tableinfo tbl_info;
  
  /* 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);
--- 110,119 ----
  typedef struct tableinfo tbl_info;
  
  /* Functions for dealing with command line arguements */
+ void AutoVacMain(void);
+ void AutoVacLoop(void);
  static cmd_args *get_cmd_args(int argc, char *argv[]);
  static void free_cmd_args(void);
  
  /* Functions for managing database lists */
  static Dllist *init_db_list(void);
***************
*** 123,135 ****
  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);
--- 126,133 ----
  static void free_db_list(Dllist *db_list);
  
  /* Functions for managing table lists */
! static void update_pg_autovacuum_table(db_info * dbi);
! static void update_table_thresholds(db_info * dbi, Oid table_oid, int vacuum_type);
  
  /* A few database helper functions */
  static int	check_stats_enabled(db_info * dbi);
***************
*** 137,142 ****
  static void db_disconnect(db_info * dbi);
  static PGresult *send_query(const char *query, db_info * dbi);
  
! /* Other Generally needed Functions */
! static void daemonize(void);
! static void log_entry(const char *logentry);
--- 135,138 ----
  static void db_disconnect(db_info * dbi);
  static PGresult *send_query(const char *query, db_info * dbi);
  
! #endif /* _AUTOVAC_H_ */
*** ./src/include/postmaster/postmaster.h.orig	2004-06-16 01:39:45.153031752 -0400
--- ./src/include/postmaster/postmaster.h	2004-06-08 00:47:42.000000000 -0400
***************
*** 29,34 ****
--- 29,35 ----
  extern bool Log_connections;
  extern bool log_hostname;
  extern char *rendezvous_name;
+ extern bool autovac_start_daemon; 
  
  #ifdef WIN32
  extern HANDLE PostmasterHandle;
*** ./src/include/storage/proc.h.orig	2004-06-05 15:31:36.000000000 -0400
--- ./src/include/storage/proc.h	2004-06-05 15:32:20.000000000 -0400
***************
*** 88,94 ****
  
  #define	DUMMY_PROC_DEFAULT	0
  #define	DUMMY_PROC_BGWRITER	1
! #define	NUM_DUMMY_PROCS		2
  
  
  /* configurable options */
--- 88,95 ----
  
  #define	DUMMY_PROC_DEFAULT	0
  #define	DUMMY_PROC_BGWRITER	1
! #define	DUMMY_PROC_AUTOVAC	2
! #define	NUM_DUMMY_PROCS		3
  
  
  /* configurable options */
*** ./src/include/utils/guc_tables.h.orig	2004-06-16 01:40:23.594817920 -0400
--- ./src/include/utils/guc_tables.h	2004-06-07 23:58:58.000000000 -0400
***************
*** 52,57 ****
--- 52,58 ----
  	COMPAT_OPTIONS_CLIENT,
  	DEVELOPER_OPTIONS,
  	COMPILE_OPTIONS,
+ 	AUTOVACUUM,
  	CUSTOM_OPTIONS
  };
  
