I have been working on integrating pg_autovacuum into the backend.  I
have used Tom's recent work on the bgwriter as an example.  This patch
accomplishes the following:

* pg_autovacuum is now started and stopped by the postmaster
* pg_autovacuum is no longer a stand alone executable
* pg_autovacuum now uses elog

I am submitting this patch for review to make sure that I'm headed in
the right direction, so please give it a cursory glance and tell me if
you see any glaring problems.

I am planning on doing much more in the next few days including:
* creating pg_autovacuum related guc variables
* create a new system table for pg_autovacuum settings
* alter pg_class (or create another new system table) to store
additional per table pg_autovacuum data which will allow per table
settings and persistent data

To use this patch, move pg_autovacuum.c into src/backend/postmaster,
move pg_autovacuum.h into src/include/postmaster and apply the patch.

Matthew O'Connor

ps, I am hoping to get this work in before feature freeze.
*** ./src/backend/bootstrap/bootstrap.c.orig	2004-06-05 15:32:02.000000000 -0400
--- ./src/backend/bootstrap/bootstrap.c	2004-06-05 15:33:13.000000000 -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/Makefile.orig	2004-06-07 01:21:43.515373849 -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-07 00:35:51.000000000 -0400
***************
*** 1,65 ****
! /* 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)
--- 1,223 ----
! /*-------------------------------------------------------------------------
!  *
!  * 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
!  */
! /*
! int			BgWriterDelay = 200;
! int			BgWriterPercent = 1;
! int			BgWriterMaxPages = 100;
! 
! int			CheckPointTimeout = 300;
! int			CheckPointWarning = 30;
! */
! 
! /*
!  * 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 bool		ckpt_active = false; */
! 
! /* static time_t	last_checkpoint_time; */
! 
! 
! 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;
  }
  
+ 
  /* 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)
***************
*** 68,75 ****
  
  	if (!new_tbl)
  	{
! 		log_entry("init_table_info: Cannot get memory");
! 		fflush(LOGOUTPUT);
  		return NULL;
  	}
  
--- 226,232 ----
  
  	if (!new_tbl)
  	{
! 		elog(ERROR, "pg_autovacuum: init_table_info: Cannot get memory");
  		return NULL;
  	}
  
***************
*** 82,89 ****
  		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,
--- 239,245 ----
  		malloc(strlen(PQgetvalue(res, row, PQfnumber(res, "schemaname"))) + 1);
  	if (!new_tbl->schema_name)
  	{
! 		elog(ERROR, "pg_autovacuum: init_table_info: malloc failed on new_tbl->schema_name");
  		return NULL;
  	}
  	strcpy(new_tbl->schema_name,
***************
*** 94,101 ****
  			   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;
  	}
  
--- 250,256 ----
  			   strlen(new_tbl->schema_name) + 6);
  	if (!new_tbl->table_name)
  	{
! 		elog(ERROR, "pg_autovacuum: init_table_info: malloc failed on new_tbl->table_name");
  		return NULL;
  	}
  
***************
*** 283,298 ****
  											* 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)
--- 438,449 ----
  											* now in the tbl_list */
  				{
  					DLAddTail(dbi->table_list, DLNewElem(init_table_info(res, i, dbi)));
! 					sprintf(logbuffer, "pg_autovacuum: added table: %s.%s", dbi->dbname,
! 							((tbl_info *) DLE_VAL(DLGetTail(dbi->table_list)))->table_name);
! 					elog(DEBUG1, logbuffer);
  				}
  			}						/* end of for loop that adds tables */
  		}
  		PQclear(res);
  		res = NULL;
  		if (args->debug >= 3)
***************
*** 310,318 ****
  
  	if (args->debug >= 1)
  	{
! 		sprintf(logbuffer, "Removing table: %s from list.", tbl->table_name);
! 		log_entry(logbuffer);
! 		fflush(LOGOUTPUT);
  	}
  	DLRemove(tbl_to_remove);
  
--- 461,468 ----
  
  	if (args->debug >= 1)
  	{
! 		sprintf(logbuffer, "pg_autovacuum: Removing table: %s from list.", tbl->table_name);
! 		elog(DEBUG1, logbuffer);
  	}
  	DLRemove(tbl_to_remove);
  
***************
*** 366,386 ****
  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 */
--- 516,540 ----
  print_table_info(tbl_info * tbl)
  {
  	sprintf(logbuffer, "  table name: %s.%s", tbl->dbi->dbname, tbl->table_name);
! 	elog(LOG, logbuffer);
! 	
  	sprintf(logbuffer, "     relid: %u;   relisshared: %i", tbl->relid, tbl->relisshared);
! 	elog(LOG, logbuffer);
! 	
  	sprintf(logbuffer, "     reltuples: %f;  relpages: %u", tbl->reltuples, tbl->relpages);
! 	elog(LOG, logbuffer);
! 	
  	sprintf(logbuffer, "     curr_analyze_count: %li; curr_vacuum_count: %li",
  			tbl->curr_analyze_count, tbl->curr_vacuum_count);
! 	elog(LOG, logbuffer);
! 	
  	sprintf(logbuffer, "     last_analyze_count: %li; last_vacuum_count: %li",
  			tbl->CountAtLastAnalyze, tbl->CountAtLastVacuum);
! 	elog(LOG, logbuffer);
! 	
  	sprintf(logbuffer, "     analyze_threshold: %li; vacuum_threshold: %li",
  			tbl->analyze_threshold, tbl->vacuum_threshold);
! 	elog(LOG, logbuffer);
  }
  
  /* 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;
  	}
  
--- 552,558 ----
  	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;
  	}
  
***************
*** 476,486 ****
  				t = 0,
  				found_match = 0;
  
! 	if (args->debug >= 2)
! 	{
! 		log_entry("updating the database list");
! 		fflush(LOGOUTPUT);
! 	}
  
  	if (dbi_template1->conn == NULL)
  	{
--- 629,635 ----
  				t = 0,
  				found_match = 0;
  
! 	elog(DEBUG2, "pg_autovacuum: updating the database list");
  
  	if (dbi_template1->conn == NULL)
  	{
***************
*** 566,577 ****
  					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)
--- 715,725 ----
  					if (args->debug >= 1)
  					{
  						sprintf(logbuffer, "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);
--- 773,781 ----
  {
  	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);
***************
*** 696,724 ****
  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);
  }
--- 841,868 ----
  print_db_info(db_info * dbi, int print_tbl_list)
  {
  	sprintf(logbuffer, "dbname: %s", (dbi->dbname) ? dbi->dbname : "(null)");
! 	elog(LOG, logbuffer);
  	
  	sprintf(logbuffer, "  oid: %u", dbi->oid);
! 	elog(LOG, logbuffer);
  	
  	sprintf(logbuffer, "  username: %s", (dbi->username) ? dbi->username : "(null)");
! 	elog(LOG, logbuffer);
  	
  	sprintf(logbuffer, "  password: %s", (dbi->password) ? dbi->password : "(null)");
! 	elog(LOG, logbuffer);
  	
  	if (dbi->conn != NULL)
! 		elog(LOG, "  conn is valid, (connected)");
  	else
! 		elog(LOG, "  conn is null, (not connected)");
  
  	sprintf(logbuffer, "  default_analyze_threshold: %li", dbi->analyze_threshold);
! 	elog(LOG, logbuffer);
  	
  	sprintf(logbuffer, "  default_vacuum_threshold: %li", dbi->vacuum_threshold);
! 	elog(LOG, logbuffer);
  	
  	if (print_tbl_list > 0)
  		print_table_list(dbi->table_list);
  }
***************
*** 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;
  	}
--- 883,889 ----
  	{
  		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 &&
--- 923,940 ----
  	if (dbi->conn == NULL)
  		return NULL;
  
! 	elog(DEBUG3, 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;
  	}
--- 943,951 ----
  		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;
--- 969,975 ----
  static cmd_args *
  get_cmd_args(int argc, char *argv[])
  {
! //	int			c;
  
  	args = (cmd_args *) malloc(sizeof(cmd_args));
  	args->sleep_base_value = SLEEPBASEVALUE;
***************
*** 838,845 ****
  	args->vacuum_scaling_factor = VACSCALINGFACTOR;
  	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;
--- 978,985 ----
  	args->vacuum_scaling_factor = VACSCALINGFACTOR;
  	args->analyze_base_threshold = -1;
  	args->analyze_scaling_factor = -1;
! //	args->debug = AUTOVACUUM_DEBUG;
! 	args->debug = 2;
  	args->user = 0;
  	args->password = 0;
  	args->host = 0;
***************
*** 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)
  		{
--- 990,996 ----
  	 * 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;
--- 1012,1017 ----
***************
*** 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,
--- 1034,1065 ----
  				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);
  	}
  
--- 1077,1095 ----
  	struct timeval now,
  				then;
  
! //	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 ****
--- 1097,1123 ----
  
  	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);
  			}
  		}
--- 1129,1135 ----
  			if (dbs->conn == NULL)
  			{					/* Serious problem: We can't connect to
  								 * template1 */
! 				elog(ERROR, "pg_autovacuum: Cannot connect to template1, exiting.");
  				exit(1);
  			}
  		}
***************
*** 1134,1142 ****
  											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);
--- 1200,1207 ----
  											snprintf(buf, sizeof(buf), "VACUUM ANALYZE %s", tbl->table_name);
  										if (args->debug >= 1)
  										{
! 											sprintf(logbuffer, "pg_autovacuum: Performing: %s", buf);
! 											elog(DEBUG1, logbuffer);
  										}
  										send_query(buf, dbs);
  										update_table_thresholds(dbs, tbl, VACUUM_ANALYZE);
***************
*** 1148,1156 ****
  										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);
--- 1213,1220 ----
  										snprintf(buf, sizeof(buf), "ANALYZE %s", tbl->table_name);
  										if (args->debug >= 1)
  										{
! 											sprintf(logbuffer, "pg_autovacuum: Performing: %s", buf);
! 											elog(DEBUG1, logbuffer);
  										}
  										send_query(buf, dbs);
  										update_table_thresholds(dbs, tbl, ANALYZE_ONLY);
***************
*** 1187,1206 ****
  
  		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
--- 1251,1269 ----
  
  		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(DEBUG1, 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;
  }
--- 1271,1275 ----
  	 */
  	free_db_list(db_list);
  	free_cmd_args();
! 	exit(0);
  }
*** ./src/backend/postmaster/postmaster.c.orig	2004-06-05 15:05:18.000000000 -0400
--- ./src/backend/postmaster/postmaster.c	2004-06-05 15:37:48.000000000 -0400
***************
*** 191,197 ****
  
  /* PIDs of special child processes; 0 when not running */
  static pid_t StartupPID = 0,
! 			BgWriterPID = 0;
  
  /* Startup/shutdown state */
  #define			NoShutdown		0
--- 191,198 ----
  
  /* PIDs of special child processes; 0 when not running */
  static pid_t StartupPID = 0,
! 			BgWriterPID = 0,
! 			AutoVacPID = 0;
  
  /* Startup/shutdown state */
  #define			NoShutdown		0
***************
*** 293,298 ****
--- 294,300 ----
  
  #define StartupDataBase()		StartChildProcess(BS_XLOG_STARTUP)
  #define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
+ #define StartAutoVac() StartChildProcess(BS_XLOG_AUTOVAC)
  
  
  /*
***************
*** 780,786 ****
  	 *
  	 * 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);
--- 782,789 ----
  	 *
  	 * 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);
***************
*** 1144,1149 ****
--- 1147,1165 ----
  				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 (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 (!pgstat_is_running)
  			pgstat_start();
***************
*** 1512,1517 ****
--- 1528,1540 ----
  								 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
***************
*** 1694,1699 ****
--- 1717,1724 ----
  		SignalChildren(SIGHUP);
  		if (BgWriterPID != 0)
  			kill(BgWriterPID, SIGHUP);
+ 		if (AutoVacPID != 0)
+ 			kill(AutoVacPID, SIGHUP);
  		load_hba();
  		load_ident();
  
***************
*** 1751,1756 ****
--- 1776,1785 ----
  			/* 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);
  			break;
  
  		case SIGINT:
***************
*** 1792,1797 ****
--- 1821,1829 ----
  			/* And tell it to shut down */
  			if (BgWriterPID != 0)
  				kill(BgWriterPID, SIGUSR2);
+ 			/* And tell it to shut down */
+ 			if (AutoVacPID != 0)
+ 				kill(AutoVacPID, SIGUSR2);
  			break;
  
  		case SIGQUIT:
***************
*** 1807,1812 ****
--- 1839,1846 ----
  				kill(StartupPID, SIGQUIT);
  			if (BgWriterPID != 0)
  				kill(BgWriterPID, SIGQUIT);
+ 			if (AutoVacPID != 0)
+ 				kill(AutoVacPID, SIGQUIT);
  			if (DLGetHead(BackendList))
  				SignalChildren(SIGQUIT);
  			ExitPostmaster(0);
***************
*** 1909,1914 ****
--- 1943,1961 ----
  			if (Shutdown > NoShutdown && BgWriterPID != 0)
  				kill(BgWriterPID, SIGUSR2);
  
+ 			/*
+ 			 * Crank up the AutoVac.  It doesn't matter if this
+ 			 * fails, we'll just try again later.
+ 			 */
+ 			Assert(AutoVacPID == 0);
+ 			AutoVacPID = StartAutoVac();
+ 			
+ 			/*
+ 			 * Go to shutdown mode if a shutdown request was pending.
+ 			 */
+ 			if (Shutdown > NoShutdown && AutoVacPID != 0)
+ 				kill(AutoVacPID, SIGUSR2);
+ 			
  			continue;
  		}
  
***************
*** 1950,1956 ****
  		 * 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")));
--- 1997,2003 ----
  		 * 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")));
***************
*** 1973,1978 ****
--- 2020,2028 ----
  		/* 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:
***************
*** 2110,2115 ****
--- 2160,2179 ----
  	}
  
  	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;
  }
  
  /*
***************
*** 3074,3079 ****
--- 3138,3147 ----
  				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/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-07 00:37:45.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,35 ----
   * (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 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 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'"
***************
*** 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);
--- 100,109 ----
  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);
***************
*** 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);
--- 130,133 ----
  static void db_disconnect(db_info * dbi);
  static PGresult *send_query(const char *query, db_info * dbi);
  
! #endif /* _AUTOVAC_H_ */
*** ./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 */
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Reply via email to