Hi,

Here's a patch to make autovacuum process TOAST tables separately from
main tables.

The most important change is that when called from autovac, vacuum does
not process the TOAST table at all.  It will only do so when the stats
for the TOAST table say that it needs vacuuming.  (A user-invoked vacuum
still processes TOAST tables normally.)

Per previous discussion, the autovac code is now doing two passes over
pg_class.

There's two things I'm not happy about in this patch:

1. it uses a List to keep the mapping of heap<->toast Oids.  This is
needed to be able to fetch the main rel's pg_autovacuum entry to process
the toast table.  This incurs in O(n^2) behavior.

2. the "expected relkind" business is gone; it's not easy to pass the
correct relkind down from autovac, and at the same time have a
reasonable thing to pass down from user-invoked vacuum.  Right now what
the patch does is check that the rel to vacuum is either
RELKIND_RELATION or _TOASTVALUE.

(I admit that my unhappiness about the second is mild, though.)

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.375
diff -c -p -r1.375 vacuum.c
*** src/backend/commands/vacuum.c	5 Jun 2008 15:47:32 -0000	1.375
--- src/backend/commands/vacuum.c	8 Aug 2008 16:42:02 -0000
*************** static BufferAccessStrategy vac_strategy
*** 213,220 ****
  static List *get_rel_oids(Oid relid, const RangeVar *vacrel,
  			 const char *stmttype);
  static void vac_truncate_clog(TransactionId frozenXID);
! static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
! 					   bool for_wraparound);
  static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
  static void scan_heap(VRelStats *vacrelstats, Relation onerel,
  		  VacPageList vacuum_pages, VacPageList fraged_pages);
--- 213,220 ----
  static List *get_rel_oids(Oid relid, const RangeVar *vacrel,
  			 const char *stmttype);
  static void vac_truncate_clog(TransactionId frozenXID);
! static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
! 		   bool for_wraparound);
  static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
  static void scan_heap(VRelStats *vacrelstats, Relation onerel,
  		  VacPageList vacuum_pages, VacPageList fraged_pages);
*************** static Size PageGetFreeSpaceWithFillFact
*** 268,273 ****
--- 268,276 ----
   * OID to be processed, and vacstmt->relation is ignored.  (The non-invalid
   * case is currently only used by autovacuum.)
   *
+  * do_toast is passed as FALSE by autovacuum, because it processes TOAST
+  * tables separately.
+  *
   * for_wraparound is used by autovacuum to let us know when it's forcing
   * a vacuum for wraparound, which should not be auto-cancelled.
   *
*************** static Size PageGetFreeSpaceWithFillFact
*** 281,287 ****
   * at transaction commit.
   */
  void
! vacuum(VacuumStmt *vacstmt, Oid relid,
  	   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
  {
  	const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
--- 284,290 ----
   * at transaction commit.
   */
  void
! vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
  	   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
  {
  	const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
*************** vacuum(VacuumStmt *vacstmt, Oid relid,
*** 433,439 ****
  			Oid			relid = lfirst_oid(cur);
  
  			if (vacstmt->vacuum)
! 				vacuum_rel(relid, vacstmt, RELKIND_RELATION, for_wraparound);
  
  			if (vacstmt->analyze)
  			{
--- 436,442 ----
  			Oid			relid = lfirst_oid(cur);
  
  			if (vacstmt->vacuum)
! 				vacuum_rel(relid, vacstmt, do_toast, for_wraparound);
  
  			if (vacstmt->analyze)
  			{
*************** vac_truncate_clog(TransactionId frozenXI
*** 975,982 ****
   *		At entry and exit, we are not inside a transaction.
   */
  static void
! vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
! 		   bool for_wraparound)
  {
  	LOCKMODE	lmode;
  	Relation	onerel;
--- 978,984 ----
   *		At entry and exit, we are not inside a transaction.
   */
  static void
! vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
  {
  	LOCKMODE	lmode;
  	Relation	onerel;
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1013,1020 ****
  		 * by autovacuum; it's used to avoid cancelling a vacuum that was
  		 * invoked in an emergency.
  		 *
! 		 * Note: this flag remains set until CommitTransaction or
! 		 * AbortTransaction.  We don't want to clear it until we reset
  		 * MyProc->xid/xmin, else OldestXmin might appear to go backwards,
  		 * which is probably Not Good.
  		 */
--- 1015,1022 ----
  		 * by autovacuum; it's used to avoid cancelling a vacuum that was
  		 * invoked in an emergency.
  		 *
! 		 * Note: these flags remain set until CommitTransaction or
! 		 * AbortTransaction.  We don't want to clear them until we reset
  		 * MyProc->xid/xmin, else OldestXmin might appear to go backwards,
  		 * which is probably Not Good.
  		 */
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1087,1096 ****
  	}
  
  	/*
! 	 * Check that it's a plain table; we used to do this in get_rel_oids() but
! 	 * seems safer to check after we've locked the relation.
  	 */
! 	if (onerel->rd_rel->relkind != expected_relkind)
  	{
  		ereport(WARNING,
  				(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
--- 1089,1099 ----
  	}
  
  	/*
! 	 * Check that it's a vacuumable table; we used to do this in get_rel_oids()
! 	 * but seems safer to check after we've locked the relation.
  	 */
! 	if (onerel->rd_rel->relkind != RELKIND_RELATION &&
! 		onerel->rd_rel->relkind != RELKIND_TOASTVALUE)
  	{
  		ereport(WARNING,
  				(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1132,1140 ****
  	LockRelationIdForSession(&onerelid, lmode);
  
  	/*
! 	 * Remember the relation's TOAST relation for later
  	 */
! 	toast_relid = onerel->rd_rel->reltoastrelid;
  
  	/*
  	 * Switch to the table owner's userid, so that any index functions are
--- 1135,1147 ----
  	LockRelationIdForSession(&onerelid, lmode);
  
  	/*
! 	 * Remember the relation's TOAST relation for later, if the caller asked
! 	 * us to process it.
  	 */
! 	if (do_toast)
! 		toast_relid = onerel->rd_rel->reltoastrelid;
! 	else
! 		toast_relid = InvalidOid;
  
  	/*
  	 * Switch to the table owner's userid, so that any index functions are
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1173,1179 ****
  	 * totally unimportant for toast relations.
  	 */
  	if (toast_relid != InvalidOid)
! 		vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE, for_wraparound);
  
  	/*
  	 * Now release the session-level lock on the master table.
--- 1180,1186 ----
  	 * totally unimportant for toast relations.
  	 */
  	if (toast_relid != InvalidOid)
! 		vacuum_rel(toast_relid, vacstmt, false, for_wraparound);
  
  	/*
  	 * Now release the session-level lock on the master table.
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.83
diff -c -p -r1.83 autovacuum.c
*** src/backend/postmaster/autovacuum.c	23 Jul 2008 20:20:10 -0000	1.83
--- src/backend/postmaster/autovacuum.c	8 Aug 2008 15:51:22 -0000
*************** static void autovac_balance_cost(void);
*** 279,285 ****
  static void do_autovacuum(void);
  static void FreeWorkerInfo(int code, Datum arg);
  
! static autovac_table *table_recheck_autovac(Oid relid);
  static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
  						  Form_pg_class classForm,
  						  PgStat_StatTabEntry *tabentry, bool *dovacuum,
--- 279,285 ----
  static void do_autovacuum(void);
  static void FreeWorkerInfo(int code, Datum arg);
  
! static autovac_table *table_recheck_autovac(Oid relid, List *table_toast_list);
  static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
  						  Form_pg_class classForm,
  						  PgStat_StatTabEntry *tabentry, bool *dovacuum,
*************** do_autovacuum(void)
*** 1821,1832 ****
  	HeapScanDesc relScan;
  	Form_pg_database dbForm;
  	List	   *table_oids = NIL;
- 	List	   *toast_oids = NIL;
  	List	   *table_toast_list = NIL;
  	ListCell   *volatile cell;
  	PgStat_StatDBEntry *shared;
  	PgStat_StatDBEntry *dbentry;
  	BufferAccessStrategy bstrategy;
  
  	/*
  	 * StartTransactionCommand and CommitTransactionCommand will automatically
--- 1821,1832 ----
  	HeapScanDesc relScan;
  	Form_pg_database dbForm;
  	List	   *table_oids = NIL;
  	List	   *table_toast_list = NIL;
  	ListCell   *volatile cell;
  	PgStat_StatDBEntry *shared;
  	PgStat_StatDBEntry *dbentry;
  	BufferAccessStrategy bstrategy;
+ 	ScanKeyData	key;
  
  	/*
  	 * StartTransactionCommand and CommitTransactionCommand will automatically
*************** do_autovacuum(void)
*** 1885,1908 ****
  	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
  
  	/*
! 	 * Scan pg_class and determine which tables to vacuum.
  	 *
! 	 * The stats subsystem collects stats for toast tables independently of
! 	 * the stats for their parent tables.  We need to check those stats since
! 	 * in cases with short, wide tables there might be proportionally much
! 	 * more activity in the toast table than in its parent.
  	 *
! 	 * Since we can only issue VACUUM against the parent table, we need to
! 	 * transpose a decision to vacuum a toast table into a decision to vacuum
! 	 * its parent.	There's no point in considering ANALYZE on a toast table,
! 	 * either.	To support this, we keep a list of OIDs of toast tables that
! 	 * need vacuuming alongside the list of regular tables.  Regular tables
! 	 * will be entered into the table list even if they appear not to need
! 	 * vacuuming; we go back and re-mark them after finding all the vacuumable
! 	 * toast tables.
  	 */
! 	relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
  
  	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
  	{
  		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
--- 1885,1914 ----
  	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
  
  	/*
! 	 * Scan pg_class to determine which tables to vacuum.
  	 *
! 	 * We do this in two passes: on the first one we collect the list of
! 	 * plain relations, and on the second one we collect TOAST tables.
! 	 * The reason for doing the second pass is that during it we want to use
! 	 * the main relation's pg_autovacuum entry if the TOAST table does not have
! 	 * any, and we cannot obtain it unless we know beforehand what's the main
! 	 * table OID.
  	 *
! 	 * We need to check TOAST tables separately because in cases with short,
! 	 * wide tables there might be proportionally much more activity in the
! 	 * TOAST table than in its parent.
  	 */
! 	ScanKeyInit(&key,
! 				Anum_pg_class_relkind,
! 				BTEqualStrategyNumber, F_CHAREQ,
! 				CharGetDatum(RELKIND_RELATION));
  
+ 	relScan = heap_beginscan(classRel, SnapshotNow, 1, &key);
+ 
+ 	/*
+ 	 * On the first pass, we collect main tables to vacuum, and also the
+ 	 * main table relid to TOAST relid mapping.
+ 	 */
  	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
  	{
  		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
*************** do_autovacuum(void)
*** 1915,1925 ****
  		bool		wraparound;
  		int			backendID;
  
- 		/* Consider only regular and toast tables. */
- 		if (classForm->relkind != RELKIND_RELATION &&
- 			classForm->relkind != RELKIND_TOASTVALUE)
- 			continue;
- 
  		relid = HeapTupleGetOid(tuple);
  
  		/* Fetch the pg_autovacuum tuple for the relation, if any */
--- 1921,1926 ----
*************** do_autovacuum(void)
*** 1952,1958 ****
  				 * vacuum for wraparound, forcibly drop it.  Otherwise just
  				 * log a complaint.
  				 */
! 				if (wraparound && classForm->relkind == RELKIND_RELATION)
  				{
  					ObjectAddress object;
  
--- 1953,1959 ----
  				 * vacuum for wraparound, forcibly drop it.  Otherwise just
  				 * log a complaint.
  				 */
! 				if (wraparound)
  				{
  					ObjectAddress object;
  
*************** do_autovacuum(void)
*** 1976,1992 ****
  				}
  			}
  		}
! 		else if (classForm->relkind == RELKIND_RELATION)
  		{
  			/* Plain relations that need work are added to table_oids */
  			if (dovacuum || doanalyze)
  				table_oids = lappend_oid(table_oids, relid);
! 			else if (OidIsValid(classForm->reltoastrelid))
  			{
- 				/*
- 				 * If it doesn't appear to need vacuuming, but it has a toast
- 				 * table, remember the association to revisit below.
- 				 */
  				av_relation *rel = palloc(sizeof(av_relation));
  
  				rel->ar_relid = relid;
--- 1977,1998 ----
  				}
  			}
  		}
! 		else
  		{
  			/* Plain relations that need work are added to table_oids */
  			if (dovacuum || doanalyze)
  				table_oids = lappend_oid(table_oids, relid);
! 
! 			/*
! 			 * Remember the association for the second pass.  Note: we must do
! 			 * this even if the table is going to be vacuumed, because we
! 			 * don't automatically vacuum toast tables along the parent table.
! 			 *
! 			 * XXX this is likely to be a performance bottleneck in the case
! 			 * of many tables.  Maybe this should use a hash instead.
! 			 */
! 			if (OidIsValid(classForm->reltoastrelid))
  			{
  				av_relation *rel = palloc(sizeof(av_relation));
  
  				rel->ar_relid = relid;
*************** do_autovacuum(void)
*** 1995,2040 ****
  				table_toast_list = lappend(table_toast_list, rel);
  			}
  		}
- 		else
- 		{
- 			/* TOAST relations that need vacuum are added to toast_oids */
- 			if (dovacuum)
- 				toast_oids = lappend_oid(toast_oids, relid);
- 		}
  
  		if (HeapTupleIsValid(avTup))
  			heap_freetuple(avTup);
  	}
  
  	heap_endscan(relScan);
- 	heap_close(avRel, AccessShareLock);
- 	heap_close(classRel, AccessShareLock);
  
! 	/*
! 	 * Add to the list of tables to vacuum, the OIDs of the tables that
! 	 * correspond to the saved OIDs of toast tables needing vacuum.
! 	 */
! 	foreach(cell, toast_oids)
  	{
! 		Oid			toastoid = lfirst_oid(cell);
! 		ListCell   *cell2;
  
! 		foreach(cell2, table_toast_list)
  		{
! 			av_relation *ar = lfirst(cell2);
  
! 			if (ar->ar_toastrelid == toastoid)
  			{
! 				table_oids = lappend_oid(table_oids, ar->ar_relid);
! 				break;
  			}
  		}
  	}
  
  	list_free_deep(table_toast_list);
  	table_toast_list = NIL;
- 	list_free(toast_oids);
- 	toast_oids = NIL;
  
  	/*
  	 * Create a buffer access strategy object for VACUUM to use.  We want to
--- 2001,2083 ----
  				table_toast_list = lappend(table_toast_list, rel);
  			}
  		}
  
  		if (HeapTupleIsValid(avTup))
  			heap_freetuple(avTup);
  	}
  
  	heap_endscan(relScan);
  
! 	/* second pass: check TOAST tables */
! 	ScanKeyInit(&key,
! 				Anum_pg_class_relkind,
! 				BTEqualStrategyNumber, F_CHAREQ,
! 				CharGetDatum(RELKIND_TOASTVALUE));
! 
! 	relScan = heap_beginscan(classRel, SnapshotNow, 1, &key);
! 	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
  	{
! 		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
! 		Form_pg_autovacuum avForm = NULL;
! 		PgStat_StatTabEntry *tabentry;
! 		HeapTuple   avTup;
! 		Oid         relid;
! 		bool		dovacuum;
! 		bool		doanalyze;
! 		bool		wraparound;
! 
! 		/*
! 		 * Skip temp tables (i.e. those in temp namespaces).  We cannot safely
! 		 * process other backends' temp tables.
! 		 */
! 		if (isAnyTempNamespace(classForm->relnamespace))
! 			continue;
  
! 		relid = HeapTupleGetOid(tuple);
! 
! 		/*
! 		 * Fetch the pg_autovacuum tuple for this rel -- either the TOAST
! 		 * table's itself, or failing that, the main rel's.
! 		 */
! 		avTup = get_pg_autovacuum_tuple_relid(avRel, relid);
! 
! 		if (!HeapTupleIsValid(avTup))
  		{
! 			ListCell   *cell;
  
! 			foreach (cell, table_toast_list)
  			{
! 				av_relation    *map = lfirst(cell);
! 
! 				if (map->ar_toastrelid == relid)
! 				{
! 					avTup = get_pg_autovacuum_tuple_relid(avRel, map->ar_relid);
! 					break;
! 				}
  			}
  		}
+ 
+ 		if (HeapTupleIsValid(avTup))
+ 			avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
+ 
+ 		/* Fetch the pgstat entry for this table */
+ 		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
+ 											 shared, dbentry);
+ 
+ 		relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
+ 								  &dovacuum, &doanalyze, &wraparound);
+ 
+ 		/* ignore analyze for toast tables */
+ 		if (dovacuum)
+ 			table_oids = lappend_oid(table_oids, relid);
  	}
  
+ 	heap_endscan(relScan);
+ 	heap_close(avRel, AccessShareLock);
+ 	heap_close(classRel, AccessShareLock);
+ 
  	list_free_deep(table_toast_list);
  	table_toast_list = NIL;
  
  	/*
  	 * Create a buffer access strategy object for VACUUM to use.  We want to
*************** do_autovacuum(void)
*** 2118,2124 ****
  		 * vacuumed in the last 500ms (PGSTAT_STAT_INTERVAL).  This is a bug.
  		 */
  		MemoryContextSwitchTo(AutovacMemCxt);
! 		tab = table_recheck_autovac(relid);
  		if (tab == NULL)
  		{
  			/* someone else vacuumed the table */
--- 2161,2167 ----
  		 * vacuumed in the last 500ms (PGSTAT_STAT_INTERVAL).  This is a bug.
  		 */
  		MemoryContextSwitchTo(AutovacMemCxt);
! 		tab = table_recheck_autovac(relid, table_toast_list);
  		if (tab == NULL)
  		{
  			/* someone else vacuumed the table */
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 2297,2310 ****
  /*
   * 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.
   *
   * Note that the returned autovac_table does not have the name fields set.
   */
  static autovac_table *
! table_recheck_autovac(Oid relid)
  {
  	Form_pg_autovacuum avForm = NULL;
  	Form_pg_class classForm;
--- 2340,2352 ----
  /*
   * table_recheck_autovac
   *
!  * Recheck whether a table still needs vacuum or analyze.  Return value is a
!  * valid autovac_table pointer if it does, NULL otherwise.
   *
   * Note that the returned autovac_table does not have the name fields set.
   */
  static autovac_table *
! table_recheck_autovac(Oid relid, List *table_toast_list)
  {
  	Form_pg_autovacuum avForm = NULL;
  	Form_pg_class classForm;
*************** table_recheck_autovac(Oid relid)
*** 2315,2325 ****
  	bool		doanalyze;
  	autovac_table *tab = NULL;
  	PgStat_StatTabEntry *tabentry;
- 	bool		doit = false;
  	PgStat_StatDBEntry *shared;
  	PgStat_StatDBEntry *dbentry;
! 	bool		wraparound,
! 				toast_wraparound = false;
  
  	/* use fresh stats */
  	autovac_refresh_stats();
--- 2357,2365 ----
  	bool		doanalyze;
  	autovac_table *tab = NULL;
  	PgStat_StatTabEntry *tabentry;
  	PgStat_StatDBEntry *shared;
  	PgStat_StatDBEntry *dbentry;
! 	bool		wraparound;
  
  	/* use fresh stats */
  	autovac_refresh_stats();
*************** table_recheck_autovac(Oid relid)
*** 2335,2343 ****
  		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);
  
--- 2375,2404 ----
  		return NULL;
  	classForm = (Form_pg_class) GETSTRUCT(classTup);
  
! 	/*
! 	 * Fetch the pg_autovacuum entry, if any.  For a toast table, also try the
! 	 * main rel's pg_autovacuum entry if there isn't one for the TOAST table
! 	 * itself.
! 	 */
  	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
  	avTup = get_pg_autovacuum_tuple_relid(avRel, relid);
+ 	if (!HeapTupleIsValid(avTup) &&
+ 		classForm->relkind == RELKIND_TOASTVALUE)
+ 	{
+ 		ListCell   *cell;
+ 
+ 		foreach (cell, table_toast_list)
+ 		{
+ 			av_relation	   *map = lfirst(cell);
+ 
+ 			if (map->ar_toastrelid == relid)
+ 			{
+ 				avTup = get_pg_autovacuum_tuple_relid(avRel, map->ar_relid);
+ 				break;
+ 			}
+ 		}
+ 	}
+ 
  	if (HeapTupleIsValid(avTup))
  		avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
  
*************** table_recheck_autovac(Oid relid)
*** 2348,2398 ****
  	relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
  							  &dovacuum, &doanalyze, &wraparound);
  
! 	/* 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;
! 			bool		toast_wraparound;
! 			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,
! 									  &toast_wraparound);
! 			/* 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;
--- 2409,2420 ----
  	relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
  							  &dovacuum, &doanalyze, &wraparound);
  
! 	/* ignore ANALYZE for toast tables */
! 	if (classForm->relkind == RELKIND_TOASTVALUE)
! 		doanalyze = false;
  
! 	/* OK, it needs something done */
! 	if (doanalyze || dovacuum)
  	{
  		int			freeze_min_age;
  		int			vac_cost_limit;
*************** table_recheck_autovac(Oid relid)
*** 2439,2445 ****
  		tab->at_freeze_min_age = freeze_min_age;
  		tab->at_vacuum_cost_limit = vac_cost_limit;
  		tab->at_vacuum_cost_delay = vac_cost_delay;
! 		tab->at_wraparound = wraparound || toast_wraparound;
  		tab->at_relname = NULL;
  		tab->at_nspname = NULL;
  		tab->at_datname = NULL;
--- 2461,2467 ----
  		tab->at_freeze_min_age = freeze_min_age;
  		tab->at_vacuum_cost_limit = vac_cost_limit;
  		tab->at_vacuum_cost_delay = vac_cost_delay;
! 		tab->at_wraparound = wraparound;
  		tab->at_relname = NULL;
  		tab->at_nspname = NULL;
  		tab->at_datname = NULL;
*************** autovacuum_do_vac_analyze(autovac_table 
*** 2633,2639 ****
  	/* Let pgstat know what we're doing */
  	autovac_report_activity(tab);
  
! 	vacuum(&vacstmt, tab->at_relid, bstrategy, tab->at_wraparound, true);
  }
  
  /*
--- 2655,2661 ----
  	/* Let pgstat know what we're doing */
  	autovac_report_activity(tab);
  
! 	vacuum(&vacstmt, tab->at_relid, false, bstrategy, tab->at_wraparound, true);
  }
  
  /*
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.295
diff -c -p -r1.295 utility.c
*** src/backend/tcop/utility.c	18 Jul 2008 20:26:06 -0000	1.295
--- src/backend/tcop/utility.c	8 Aug 2008 15:51:22 -0000
*************** ProcessUtility(Node *parsetree,
*** 836,842 ****
  			break;
  
  		case T_VacuumStmt:
! 			vacuum((VacuumStmt *) parsetree, InvalidOid, NULL, false,
  				   isTopLevel);
  			break;
  
--- 836,842 ----
  			break;
  
  		case T_VacuumStmt:
! 			vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false,
  				   isTopLevel);
  			break;
  
Index: src/include/commands/vacuum.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/commands/vacuum.h,v
retrieving revision 1.79
diff -c -p -r1.79 vacuum.h
*** src/include/commands/vacuum.h	1 Jul 2008 10:33:09 -0000	1.79
--- src/include/commands/vacuum.h	8 Aug 2008 15:51:22 -0000
*************** extern int	vacuum_freeze_min_age;
*** 125,131 ****
  
  
  /* in commands/vacuum.c */
! extern void vacuum(VacuumStmt *vacstmt, Oid relid,
  	   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel);
  extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
  				 int *nindexes, Relation **Irel);
--- 125,131 ----
  
  
  /* in commands/vacuum.c */
! extern void vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
  	   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel);
  extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
  				 int *nindexes, Relation **Irel);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to