Hi,

This is the first non-trivial patch to autovacuum multiple workers.

This patch that adds the "recheck" logic to autovacuum worker.  With
this, the worker first builds its table list and then rechecks pgstat
before vacuuming each table to verify that no one has vacuumed the table
in the meantime, before vacuuming it.

In the current autovacuum world this only means that a worker will not
vacuum a table that a user has vacuumed manually.  As discussed, it will
be much more useful as soon as multiple workers are running
concurrently.

To do this, I separated the task of calculating autovacuum parameters
(freeze_min_age, vacuum cost limit and delay, etc) from the autovac
equation calculation (freeze_max_age, pg_class.reltuples, etc).

We now keep track of three lists at the initial pg_class scan:

1. tables that need vacuum or analyze, per equations
2. tables not in (1) that have toast tables
3. toast tables that need vacuum

Then we append those tables in (2) whose toast tables are in (3), to the
(1) list.  The rest are discarded.  So when we need to do the
rechecking, we need to process only those tables that actually needed
vacuuming.  With the previous coding, we would end up rechecking almost
all tables every time (to be exact, all tables that have a toast table).

The autovacuum parameters are only calculated in the second pass (the
rechecking).  The first pass only yields boolean parameters.

Unless there are objections I'll apply this tomorrow.

-- 
Alvaro Herrera                                http://www.PlanetPostgreSQL.org
"La naturaleza, tan frágil, tan expuesta a la muerte... y tan viva"
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.39
diff -c -p -r1.39 autovacuum.c
*** src/backend/postmaster/autovacuum.c	27 Mar 2007 20:36:03 -0000	1.39
--- src/backend/postmaster/autovacuum.c	27 Mar 2007 20:43:31 -0000
*************** typedef struct autovac_dbase
*** 91,96 ****
--- 91,103 ----
  	PgStat_StatDBEntry *ad_entry;
  } autovac_dbase;
  
+ /* struct to keep track of tables to vacuum and/or analyze, in 1st pass */
+ typedef struct av_relation
+ {
+ 	Oid		ar_relid;
+ 	Oid		ar_toastrelid;
+ } av_relation;
+ 
  /* struct to keep track of tables to vacuum and/or analyze, after rechecking */
  typedef struct autovac_table
  {
*************** NON_EXEC_STATIC void AutoVacLauncherMain
*** 121,137 ****
  static void do_start_worker(void);
  static void do_autovacuum(Oid dbid);
  static List *autovac_get_database_list(void);
! static void test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
! 					 Form_pg_class classForm,
! 					 Form_pg_autovacuum avForm,
! 					 List **vacuum_tables,
! 					 List **toast_table_ids);
  static void autovacuum_do_vac_analyze(Oid relid, bool dovacuum,
  						  bool doanalyze, int freeze_min_age);
  static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid);
  static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
  						  PgStat_StatDBEntry *shared,
  						  PgStat_StatDBEntry *dbentry);
  static void autovac_report_activity(VacuumStmt *vacstmt, Oid relid);
  static void avl_sighup_handler(SIGNAL_ARGS);
  static void avlauncher_shutdown(SIGNAL_ARGS);
--- 128,152 ----
  static void do_start_worker(void);
  static void do_autovacuum(Oid dbid);
  static List *autovac_get_database_list(void);
! 
! static void relation_check_autovac(Oid relid, Form_pg_class classForm,
! 					   Form_pg_autovacuum avForm, PgStat_StatTabEntry *tabentry,
! 					   List **table_oids, List **table_toast_list,
! 					   List **toast_oids);
! static autovac_table *table_recheck_autovac(Oid relid,
! 											PgStat_StatDBEntry *shared,
! 											PgStat_StatDBEntry *dbentry);
  static void autovacuum_do_vac_analyze(Oid relid, bool dovacuum,
  						  bool doanalyze, int freeze_min_age);
  static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid);
  static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
  						  PgStat_StatDBEntry *shared,
  						  PgStat_StatDBEntry *dbentry);
+ static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
+ 						  Form_pg_class classForm,
+ 						  PgStat_StatTabEntry *tabentry, bool *dovacuum,
+ 						  bool *doanalyze);
+ static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid);
  static void autovac_report_activity(VacuumStmt *vacstmt, Oid relid);
  static void avl_sighup_handler(SIGNAL_ARGS);
  static void avlauncher_shutdown(SIGNAL_ARGS);
*************** do_autovacuum(Oid dbid)
*** 872,879 ****
  	HeapTuple	tuple;
  	HeapScanDesc relScan;
  	Form_pg_database dbForm;
! 	List	   *vacuum_tables = NIL;
! 	List	   *toast_table_ids = NIL;
  	ListCell   *cell;
  	PgStat_StatDBEntry *shared;
  	PgStat_StatDBEntry *dbentry;
--- 887,895 ----
  	HeapTuple	tuple;
  	HeapScanDesc relScan;
  	Form_pg_database dbForm;
! 	List	   *table_oids = NIL;
! 	List	   *toast_oids = NIL;
! 	List	   *table_toast_list = NIL;
  	ListCell   *cell;
  	PgStat_StatDBEntry *shared;
  	PgStat_StatDBEntry *dbentry;
*************** do_autovacuum(Oid dbid)
*** 979,986 ****
  		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  											 shared, dbentry);
  
! 		test_rel_for_autovac(relid, tabentry, classForm, avForm,
! 							 &vacuum_tables, &toast_table_ids);
  
  		if (HeapTupleIsValid(avTup))
  			heap_freetuple(avTup);
--- 995,1002 ----
  		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  											 shared, dbentry);
  
! 		relation_check_autovac(relid, classForm, avForm, tabentry,
! 							   &table_oids, &table_toast_list, &toast_oids);
  
  		if (HeapTupleIsValid(avTup))
  			heap_freetuple(avTup);
*************** do_autovacuum(Oid dbid)
*** 990,1028 ****
  	heap_close(avRel, AccessShareLock);
  	heap_close(classRel, AccessShareLock);
  
! 	/*
! 	 * Perform operations on collected tables.
! 	 */
! 	foreach(cell, vacuum_tables)
  	{
! 		autovac_table *tab = lfirst(cell);
  
  		CHECK_FOR_INTERRUPTS();
  
  		/*
! 		 * Check to see if we need to force vacuuming of this table because
! 		 * its toast table needs it.
  		 */
! 		if (OidIsValid(tab->at_toastrelid) && !tab->at_dovacuum &&
! 			list_member_oid(toast_table_ids, tab->at_toastrelid))
  		{
! 			tab->at_dovacuum = true;
! 			elog(DEBUG2, "autovac: VACUUM %u because of TOAST table",
! 				 tab->at_relid);
! 		}
! 
! 		/* Otherwise, ignore table if it needs no work */
! 		if (!tab->at_dovacuum && !tab->at_doanalyze)
  			continue;
  
  		/* Set the vacuum cost parameters for this table */
  		VacuumCostDelay = tab->at_vacuum_cost_delay;
  		VacuumCostLimit = tab->at_vacuum_cost_limit;
  
  		autovacuum_do_vac_analyze(tab->at_relid,
  								  tab->at_dovacuum,
  								  tab->at_doanalyze,
  								  tab->at_freeze_min_age);
  	}
  
  	/*
--- 1006,1070 ----
  	heap_close(avRel, AccessShareLock);
  	heap_close(classRel, AccessShareLock);
  
! 	/* mix the TOAST table oids into the plain table OID list */
! 	if (list_length(toast_oids) > 0)
  	{
! 		foreach(cell, table_toast_list)
! 		{
! 			av_relation *ar = lfirst(cell);
! 
! 			if (list_member_oid(toast_oids, ar->ar_toastrelid))
! 				table_oids = lappend_oid(table_oids, ar->ar_relid);
! 		}
! 	}
! 	list_free_deep(table_toast_list);
! 	table_toast_list = NIL;
! 	list_free(toast_oids);
! 	toast_oids = NIL;
! 
! 	/* Perform operations on collected tables. */
! 	foreach(cell, table_oids)
! 	{
! 		Oid		relid = lfirst_oid(cell);
! 		autovac_table *tab;
  
  		CHECK_FOR_INTERRUPTS();
  
  		/*
! 		 * Check whether pgstat data still says we need to vacuum this table.
! 		 * It could have changed if other worker processed the table while we
! 		 * weren't looking; and pg_autovacuum parameters could have changed
! 		 * as well.
! 		 *
! 		 * We need fresh pgstat data for this.
! 		 *
! 		 * FIXME we ignore the possibility that the table was finished being
! 		 * vacuumed in the last 500ms (PGSTAT_STAT_INTERVAL).  This is a bug.
  		 */
! 		pgstat_clear_snapshot();
! 		tab = table_recheck_autovac(relid, shared, dbentry);
! 		if (tab == NULL)
  		{
! 			/* someone else vacuumed the table */
  			continue;
+ 		}
+ 		/* Ok, good to go! */
  
  		/* Set the vacuum cost parameters for this table */
  		VacuumCostDelay = tab->at_vacuum_cost_delay;
  		VacuumCostLimit = tab->at_vacuum_cost_limit;
  
+ 		elog(DEBUG2, "autovac: will%s%s %s",
+ 			 (tab->at_dovacuum ? " VACUUM" : ""),
+ 			 (tab->at_doanalyze ? " ANALYZE" : ""),
+ 			 get_rel_name(relid));
+ 
  		autovacuum_do_vac_analyze(tab->at_relid,
  								  tab->at_dovacuum,
  								  tab->at_doanalyze,
  								  tab->at_freeze_min_age);
+ 		/* be tidy */
+ 		pfree(tab);
  	}
  
  	/*
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 1089,1098 ****
  }
  
  /*
!  * test_rel_for_autovac
   *
!  * Check whether a table needs to be vacuumed or analyzed.	Add it to the
!  * appropriate output list if so.
   *
   * A table needs to be vacuumed if the number of dead tuples exceeds a
   * threshold.  This threshold is calculated as
--- 1131,1329 ----
  }
  
  /*
!  * relation_check_autovac
!  *
!  * For a given relation (either a plain table or TOAST table), check whether it
!  * needs vacuum or analyze.
!  *
!  * Plain tables that need either are added to the table_list.  TOAST tables
!  * that need vacuum are added to toast_list.  Plain tables that don't need
!  * either but which have a TOAST table are added, as a struct, to
!  * table_toast_list.  The latter is to allow appending the OIDs of the plain
!  * tables whose TOAST table needs vacuuming into the plain tables list, which
!  * allows us to substantially reduce the number of "rechecks" that we need to
!  * do later on.
!  */
! static void
! relation_check_autovac(Oid relid, Form_pg_class classForm,
! 					   Form_pg_autovacuum avForm, PgStat_StatTabEntry *tabentry,
! 					   List **table_oids, List **table_toast_list,
! 					   List **toast_oids)
! {
! 	bool	dovacuum;
! 	bool	doanalyze;
! 
! 	relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
! 							  &dovacuum, &doanalyze);
! 
! 	if (classForm->relkind == RELKIND_TOASTVALUE)
! 	{
! 		if (dovacuum)
! 			*toast_oids = lappend_oid(*toast_oids, relid);
! 	}
! 	else
! 	{
! 		Assert(classForm->relkind == RELKIND_RELATION);
! 
! 		if (dovacuum || doanalyze)
! 			*table_oids = lappend_oid(*table_oids, relid);
! 		else if (OidIsValid(classForm->reltoastrelid))
! 		{
! 			av_relation	   *rel = palloc(sizeof(av_relation));
! 
! 			rel->ar_relid = relid;
! 			rel->ar_toastrelid = classForm->reltoastrelid;
! 
! 			*table_toast_list = lappend(*table_toast_list, rel);
! 		}
! 	}
! }
! 
! /*
!  * table_recheck_autovac
!  *
!  * Recheck whether a plain table still needs vacuum or analyze; be it because
!  * it does directly, or because its TOAST table does.  Return value is a valid
!  * autovac_table pointer if it does, NULL otherwise.
!  */
! static autovac_table *
! table_recheck_autovac(Oid relid, PgStat_StatDBEntry *shared, PgStat_StatDBEntry *dbentry)
! {
! 	Form_pg_autovacuum avForm = NULL;
! 	Form_pg_class classForm;
! 	HeapTuple	classTup;
! 	HeapTuple	avTup;
! 	Relation	avRel;
! 	bool		dovacuum;
! 	bool		doanalyze;
! 	autovac_table *tab = NULL;
! 	PgStat_StatTabEntry *tabentry;
! 	bool		doit = false;
! 
! 	/* fetch the relation's relcache entry */
! 	classTup = SearchSysCacheCopy(RELOID,
! 							  ObjectIdGetDatum(relid),
! 							  0, 0, 0);
! 	if (!HeapTupleIsValid(classTup))
! 		return NULL;
! 	classForm = (Form_pg_class) GETSTRUCT(classTup);
! 
! 	/* fetch the pg_autovacuum entry, if any */
! 	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
! 	avTup = get_pg_autovacuum_tuple_relid(avRel, relid);
! 	if (HeapTupleIsValid(avTup))
! 		avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
! 
! 	/* fetch the pgstat table entry */
! 	tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
! 										 shared, dbentry);
! 
! 	relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
! 							  &dovacuum, &doanalyze);
! 
! 	/* OK, it needs vacuum by itself */
! 	if (dovacuum)
! 		doit = true;
! 	/* it doesn't need vacuum, but what about it's TOAST table? */
! 	else if (OidIsValid(classForm->reltoastrelid))
! 	{
! 		Oid		toastrelid = classForm->reltoastrelid;
! 		HeapTuple	toastClassTup;
! 
! 		toastClassTup = SearchSysCacheCopy(RELOID,
! 										   ObjectIdGetDatum(toastrelid),
! 										   0, 0, 0);
! 		if (HeapTupleIsValid(toastClassTup))
! 		{
! 			bool			toast_dovacuum;
! 			bool			toast_doanalyze;
! 			Form_pg_class	toastClassForm;
! 			PgStat_StatTabEntry *toasttabentry;
! 
! 			toastClassForm = (Form_pg_class) GETSTRUCT(toastClassTup);
! 			toasttabentry = get_pgstat_tabentry_relid(toastrelid,
! 													  toastClassForm->relisshared,
! 													  shared, dbentry);
! 
! 			/* note we use the pg_autovacuum entry for the main table */
! 			relation_needs_vacanalyze(toastrelid, avForm, toastClassForm,
! 									  toasttabentry, &toast_dovacuum,
! 									  &toast_doanalyze);
! 			/* we only consider VACUUM for toast tables */
! 			if (toast_dovacuum)
! 			{
! 				dovacuum = true;
! 				doit = true;
! 			}
! 
! 			heap_freetuple(toastClassTup);
! 		}
! 	}
! 
! 	if (doanalyze)
! 		doit = true;
! 
! 	if (doit)
! 	{
! 		int			freeze_min_age;
! 		int			vac_cost_limit;
! 		int			vac_cost_delay;
! 
! 		/*
! 		 * Calculate the vacuum cost parameters and the minimum freeze age.  If
! 		 * there is a tuple in pg_autovacuum, use it; else, use the GUC
! 		 * defaults.  Note that the fields may contain "-1" (or indeed any
! 		 * negative value), which means use the GUC defaults for each setting.
! 		 */
! 		if (avForm != NULL)
! 		{
! 			vac_cost_limit = (avForm->vac_cost_limit >= 0) ?
! 				avForm->vac_cost_limit :
! 				((autovacuum_vac_cost_limit >= 0) ?
! 				 autovacuum_vac_cost_limit : VacuumCostLimit);
! 
! 			vac_cost_delay = (avForm->vac_cost_delay >= 0) ?
! 				avForm->vac_cost_delay :
! 				((autovacuum_vac_cost_delay >= 0) ?
! 				 autovacuum_vac_cost_delay : VacuumCostDelay);
! 
! 			freeze_min_age = (avForm->freeze_min_age >= 0) ?
! 				avForm->freeze_min_age : default_freeze_min_age;
! 		}
! 		else
! 		{
! 			vac_cost_limit = (autovacuum_vac_cost_limit >= 0) ?
! 				autovacuum_vac_cost_limit : VacuumCostLimit;
! 
! 			vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
! 				autovacuum_vac_cost_delay : VacuumCostDelay;
! 
! 			freeze_min_age = default_freeze_min_age;
! 		}
! 
! 		tab = palloc(sizeof(autovac_table));
! 		tab->at_relid = relid;
! 		tab->at_dovacuum = dovacuum;
! 		tab->at_doanalyze = doanalyze;
! 		tab->at_freeze_min_age = freeze_min_age;
! 		tab->at_vacuum_cost_limit = vac_cost_limit;
! 		tab->at_vacuum_cost_delay = vac_cost_delay;
! 	}
! 
! 	heap_close(avRel, AccessShareLock);
! 	if (HeapTupleIsValid(avTup))
! 		heap_freetuple(avTup);
! 	heap_freetuple(classTup);
! 
! 	return tab;
! }
! 
! /*
!  * relation_needs_vacanalyze
   *
!  * Check whether a relation needs to be vacuumed or analyzed; return each into
!  * "dovacuum" and "doanalyze", respectively.  avForm and tabentry can be NULL,
!  * classForm shouldn't.
   *
   * A table needs to be vacuumed if the number of dead tuples exceeds a
   * threshold.  This threshold is calculated as
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 1119,1134 ****
   * autovacuum_vacuum_scale_factor GUC variable.  Ditto for analyze.
   */
  static void
! test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry,
! 					 Form_pg_class classForm,
! 					 Form_pg_autovacuum avForm,
! 					 List **vacuum_tables,
! 					 List **toast_table_ids)
  {
- 	bool		force_vacuum;
- 	bool		dovacuum;
- 	bool		doanalyze;
  	float4		reltuples;		/* pg_class.reltuples */
  	/* constants from pg_autovacuum or GUC variables */
  	int			vac_base_thresh,
  				anl_base_thresh;
--- 1350,1365 ----
   * autovacuum_vacuum_scale_factor GUC variable.  Ditto for analyze.
   */
  static void
! relation_needs_vacanalyze(Oid relid,
! 						  Form_pg_autovacuum avForm,
! 						  Form_pg_class classForm,
! 						  PgStat_StatTabEntry *tabentry,
! 						  /* output params below */
! 						  bool *dovacuum,
! 						  bool *doanalyze)
  {
  	float4		reltuples;		/* pg_class.reltuples */
+ 	bool		force_vacuum;
  	/* constants from pg_autovacuum or GUC variables */
  	int			vac_base_thresh,
  				anl_base_thresh;
*************** test_rel_for_autovac(Oid relid, PgStat_S
*** 1140,1157 ****
  	/* number of vacuum (resp. analyze) tuples at this time */
  	float4		vactuples,
  				anltuples;
- 	/* freeze parameters */
- 	int			freeze_min_age;
- 	int			freeze_max_age;
  	TransactionId xidForceLimit;
! 	/* cost-based vacuum delay parameters */
! 	int			vac_cost_limit;
! 	int			vac_cost_delay;
  
  	/*
! 	 * If there is a tuple in pg_autovacuum, use it; else, use the GUC
! 	 * defaults.  Note that the fields may contain "-1" (or indeed any
! 	 * negative value), which means use the GUC defaults for each setting.
  	 */
  	if (avForm != NULL)
  	{
--- 1371,1387 ----
  	/* number of vacuum (resp. analyze) tuples at this time */
  	float4		vactuples,
  				anltuples;
  	TransactionId xidForceLimit;
! 	int			freeze_max_age;
! 
! 	AssertArg(classForm != NULL);
! 	AssertArg(OidIsValid(relid));
  
  	/*
! 	 * Determine vacuum/analyze equation parameters.  If there is a tuple in
! 	 * pg_autovacuum, use it; else, use the GUC defaults.  Note that the fields
! 	 * may contain "-1" (or indeed any negative value), which means use the GUC
! 	 * defaults for each setting.
  	 */
  	if (avForm != NULL)
  	{
*************** test_rel_for_autovac(Oid relid, PgStat_S
*** 1165,1185 ****
  		anl_base_thresh = (avForm->anl_base_thresh >= 0) ?
  			avForm->anl_base_thresh : autovacuum_anl_thresh;
  
- 		freeze_min_age = (avForm->freeze_min_age >= 0) ?
- 			avForm->freeze_min_age : default_freeze_min_age;
  		freeze_max_age = (avForm->freeze_max_age >= 0) ?
  			Min(avForm->freeze_max_age, autovacuum_freeze_max_age) :
  			autovacuum_freeze_max_age;
- 
- 		vac_cost_limit = (avForm->vac_cost_limit >= 0) ?
- 			avForm->vac_cost_limit :
- 			((autovacuum_vac_cost_limit >= 0) ?
- 			 autovacuum_vac_cost_limit : VacuumCostLimit);
- 
- 		vac_cost_delay = (avForm->vac_cost_delay >= 0) ?
- 			avForm->vac_cost_delay :
- 			((autovacuum_vac_cost_delay >= 0) ?
- 			 autovacuum_vac_cost_delay : VacuumCostDelay);
  	}
  	else
  	{
--- 1395,1403 ----
*************** test_rel_for_autovac(Oid relid, PgStat_S
*** 1189,1202 ****
  		anl_scale_factor = autovacuum_anl_scale;
  		anl_base_thresh = autovacuum_anl_thresh;
  
- 		freeze_min_age = default_freeze_min_age;
  		freeze_max_age = autovacuum_freeze_max_age;
- 
- 		vac_cost_limit = (autovacuum_vac_cost_limit >= 0) ?
- 			autovacuum_vac_cost_limit : VacuumCostLimit;
- 
- 		vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
- 			autovacuum_vac_cost_delay : VacuumCostDelay;
  	}
  
  	/* Force vacuum if table is at risk of wraparound */
--- 1407,1413 ----
*************** test_rel_for_autovac(Oid relid, PgStat_S
*** 1209,1290 ****
  
  	/* User disabled it in pg_autovacuum?  (But ignore if at risk) */
  	if (avForm && !avForm->enabled && !force_vacuum)
- 		return;
- 
- 	if (PointerIsValid(tabentry))
  	{
! 		reltuples = classForm->reltuples;
! 		vactuples = tabentry->n_dead_tuples;
! 		anltuples = tabentry->n_live_tuples + tabentry->n_dead_tuples -
! 			tabentry->last_anl_tuples;
! 
! 		vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
! 		anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
! 
! 		/*
! 		 * Note that we don't need to take special consideration for stat
! 		 * reset, because if that happens, the last vacuum and analyze counts
! 		 * will be reset too.
! 		 */
! 		elog(DEBUG3, "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
! 			 NameStr(classForm->relname),
! 			 vactuples, vacthresh, anltuples, anlthresh);
! 
! 		/* Determine if this table needs vacuum or analyze. */
! 		dovacuum = force_vacuum || (vactuples > vacthresh);
! 		doanalyze = (anltuples > anlthresh);
  	}
  	else
  	{
! 		/*
! 		 * Skip a table not found in stat hash, unless we have to force
! 		 * vacuum for anti-wrap purposes.  If it's not acted upon, there's
! 		 * no need to vacuum it.
! 		 */
! 		dovacuum = force_vacuum;
! 		doanalyze = false;
  	}
  
  	/* ANALYZE refuses to work with pg_statistics */
  	if (relid == StatisticRelationId)
! 		doanalyze = false;
! 
! 	Assert(CurrentMemoryContext == AutovacMemCxt);
! 
! 	if (classForm->relkind == RELKIND_RELATION)
! 	{
! 		if (dovacuum || doanalyze)
! 			elog(DEBUG2, "autovac: will%s%s %s",
! 				 (dovacuum ? " VACUUM" : ""),
! 				 (doanalyze ? " ANALYZE" : ""),
! 				 NameStr(classForm->relname));
! 
! 		/*
! 		 * we must record tables that have a toast table, even if we currently
! 		 * don't think they need vacuuming.
! 		 */
! 		if (dovacuum || doanalyze || OidIsValid(classForm->reltoastrelid))
! 		{
! 			autovac_table *tab;
! 
! 			tab = (autovac_table *) palloc(sizeof(autovac_table));
! 			tab->at_relid = relid;
! 			tab->at_toastrelid = classForm->reltoastrelid;
! 			tab->at_dovacuum = dovacuum;
! 			tab->at_doanalyze = doanalyze;
! 			tab->at_freeze_min_age = freeze_min_age;
! 			tab->at_vacuum_cost_limit = vac_cost_limit;
! 			tab->at_vacuum_cost_delay = vac_cost_delay;
! 
! 			*vacuum_tables = lappend(*vacuum_tables, tab);
! 		}
! 	}
! 	else
! 	{
! 		Assert(classForm->relkind == RELKIND_TOASTVALUE);
! 		if (dovacuum)
! 			*toast_table_ids = lappend_oid(*toast_table_ids, relid);
! 	}
  }
  
  /*
--- 1420,1471 ----
  
  	/* User disabled it in pg_autovacuum?  (But ignore if at risk) */
  	if (avForm && !avForm->enabled && !force_vacuum)
  	{
! 		*doanalyze = false;
! 		*dovacuum = false;
! 		return;
  	}
  	else
  	{
! 		if (PointerIsValid(tabentry))
! 		{
! 			reltuples = classForm->reltuples;
! 			vactuples = tabentry->n_dead_tuples;
! 			anltuples = tabentry->n_live_tuples + tabentry->n_dead_tuples -
! 				tabentry->last_anl_tuples;
! 
! 			vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
! 			anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
! 
! 			/*
! 			 * Note that we don't need to take special consideration for stat
! 			 * reset, because if that happens, the last vacuum and analyze
! 			 * counts will be reset too.
! 			 */
! 			elog(DEBUG3,
! 				 "%s: vac: %.0f (threshold %.0f), anl: %.0f (threshold %.0f)",
! 				 NameStr(classForm->relname),
! 				 vactuples, vacthresh, anltuples, anlthresh);
! 
! 			/* Determine if this table needs vacuum or analyze. */
! 			*dovacuum = force_vacuum || (vactuples > vacthresh);
! 			*doanalyze = (anltuples > anlthresh);
! 		}
! 		else
! 		{
! 			/*
! 			 * Skip a table not found in stat hash, unless we have to force
! 			 * vacuum for anti-wrap purposes.  If it's not acted upon, there's
! 			 * no need to vacuum it.
! 			 */
! 			*dovacuum = force_vacuum;
! 			*doanalyze = false;
! 		}
  	}
  
  	/* ANALYZE refuses to work with pg_statistics */
  	if (relid == StatisticRelationId)
! 		*doanalyze = false;
  }
  
  /*
---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to