mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	Have autovacuum consider processing TOAST tables separately from their
main tables. This requires vacuum() to accept processing a toast table standalone, so there's a user-visible change in that it's now possible (for a superuser) to execute "VACUUM pg_toast.pg_toast_XXX".
This commit is contained in:
		
							parent
							
								
									010eebf164
								
							
						
					
					
						commit
						3ccde312ec
					
				@ -13,7 +13,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.375 2008/06/05 15:47:32 alvherre Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.376 2008/08/13 00:07:50 alvherre Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -213,7 +213,7 @@ static BufferAccessStrategy vac_strategy;
 | 
				
			|||||||
static List *get_rel_oids(Oid relid, const RangeVar *vacrel,
 | 
					static List *get_rel_oids(Oid relid, const RangeVar *vacrel,
 | 
				
			||||||
			 const char *stmttype);
 | 
								 const char *stmttype);
 | 
				
			||||||
static void vac_truncate_clog(TransactionId frozenXID);
 | 
					static void vac_truncate_clog(TransactionId frozenXID);
 | 
				
			||||||
static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
 | 
					static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
 | 
				
			||||||
		   bool for_wraparound);
 | 
							   bool for_wraparound);
 | 
				
			||||||
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
 | 
					static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
 | 
				
			||||||
static void scan_heap(VRelStats *vacrelstats, Relation onerel,
 | 
					static void scan_heap(VRelStats *vacrelstats, Relation onerel,
 | 
				
			||||||
@ -268,6 +268,9 @@ static Size PageGetFreeSpaceWithFillFactor(Relation relation, Page page);
 | 
				
			|||||||
 * OID to be processed, and vacstmt->relation is ignored.  (The non-invalid
 | 
					 * OID to be processed, and vacstmt->relation is ignored.  (The non-invalid
 | 
				
			||||||
 * case is currently only used by autovacuum.)
 | 
					 * 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
 | 
					 * for_wraparound is used by autovacuum to let us know when it's forcing
 | 
				
			||||||
 * a vacuum for wraparound, which should not be auto-cancelled.
 | 
					 * a vacuum for wraparound, which should not be auto-cancelled.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@ -281,7 +284,7 @@ static Size PageGetFreeSpaceWithFillFactor(Relation relation, Page page);
 | 
				
			|||||||
 * at transaction commit.
 | 
					 * at transaction commit.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
vacuum(VacuumStmt *vacstmt, Oid relid,
 | 
					vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
 | 
				
			||||||
	   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
 | 
						   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
 | 
						const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
 | 
				
			||||||
@ -433,7 +436,7 @@ vacuum(VacuumStmt *vacstmt, Oid relid,
 | 
				
			|||||||
			Oid			relid = lfirst_oid(cur);
 | 
								Oid			relid = lfirst_oid(cur);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (vacstmt->vacuum)
 | 
								if (vacstmt->vacuum)
 | 
				
			||||||
				vacuum_rel(relid, vacstmt, RELKIND_RELATION, for_wraparound);
 | 
									vacuum_rel(relid, vacstmt, do_toast, for_wraparound);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (vacstmt->analyze)
 | 
								if (vacstmt->analyze)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -975,8 +978,7 @@ vac_truncate_clog(TransactionId frozenXID)
 | 
				
			|||||||
 *		At entry and exit, we are not inside a transaction.
 | 
					 *		At entry and exit, we are not inside a transaction.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
 | 
					vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 | 
				
			||||||
		   bool for_wraparound)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOCKMODE	lmode;
 | 
						LOCKMODE	lmode;
 | 
				
			||||||
	Relation	onerel;
 | 
						Relation	onerel;
 | 
				
			||||||
@ -1013,8 +1015,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
 | 
				
			|||||||
		 * by autovacuum; it's used to avoid cancelling a vacuum that was
 | 
							 * by autovacuum; it's used to avoid cancelling a vacuum that was
 | 
				
			||||||
		 * invoked in an emergency.
 | 
							 * invoked in an emergency.
 | 
				
			||||||
		 *
 | 
							 *
 | 
				
			||||||
		 * Note: this flag remains set until CommitTransaction or
 | 
							 * Note: these flags remain set until CommitTransaction or
 | 
				
			||||||
		 * AbortTransaction.  We don't want to clear it until we reset
 | 
							 * AbortTransaction.  We don't want to clear them until we reset
 | 
				
			||||||
		 * MyProc->xid/xmin, else OldestXmin might appear to go backwards,
 | 
							 * MyProc->xid/xmin, else OldestXmin might appear to go backwards,
 | 
				
			||||||
		 * which is probably Not Good.
 | 
							 * which is probably Not Good.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
@ -1087,10 +1089,11 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Check that it's a plain table; we used to do this in get_rel_oids() but
 | 
						 * Check that it's a vacuumable table; we used to do this in get_rel_oids()
 | 
				
			||||||
	 * seems safer to check after we've locked the relation.
 | 
						 * but seems safer to check after we've locked the relation.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (onerel->rd_rel->relkind != expected_relkind)
 | 
						if (onerel->rd_rel->relkind != RELKIND_RELATION &&
 | 
				
			||||||
 | 
							onerel->rd_rel->relkind != RELKIND_TOASTVALUE)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ereport(WARNING,
 | 
							ereport(WARNING,
 | 
				
			||||||
				(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
 | 
									(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
 | 
				
			||||||
@ -1132,9 +1135,13 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
 | 
				
			|||||||
	LockRelationIdForSession(&onerelid, lmode);
 | 
						LockRelationIdForSession(&onerelid, lmode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Remember the relation's TOAST relation for later
 | 
						 * 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;
 | 
							toast_relid = onerel->rd_rel->reltoastrelid;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							toast_relid = InvalidOid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Switch to the table owner's userid, so that any index functions are
 | 
						 * Switch to the table owner's userid, so that any index functions are
 | 
				
			||||||
@ -1173,7 +1180,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
 | 
				
			|||||||
	 * totally unimportant for toast relations.
 | 
						 * totally unimportant for toast relations.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (toast_relid != InvalidOid)
 | 
						if (toast_relid != InvalidOid)
 | 
				
			||||||
		vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE, for_wraparound);
 | 
							vacuum_rel(toast_relid, vacstmt, false, for_wraparound);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Now release the session-level lock on the master table.
 | 
						 * Now release the session-level lock on the master table.
 | 
				
			||||||
 | 
				
			|||||||
@ -55,7 +55,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.83 2008/07/23 20:20:10 alvherre Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.84 2008/08/13 00:07:50 alvherre Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -93,6 +93,7 @@
 | 
				
			|||||||
#include "storage/procarray.h"
 | 
					#include "storage/procarray.h"
 | 
				
			||||||
#include "storage/sinvaladt.h"
 | 
					#include "storage/sinvaladt.h"
 | 
				
			||||||
#include "tcop/tcopprot.h"
 | 
					#include "tcop/tcopprot.h"
 | 
				
			||||||
 | 
					#include "utils/dynahash.h"
 | 
				
			||||||
#include "utils/flatfiles.h"
 | 
					#include "utils/flatfiles.h"
 | 
				
			||||||
#include "utils/fmgroids.h"
 | 
					#include "utils/fmgroids.h"
 | 
				
			||||||
#include "utils/lsyscache.h"
 | 
					#include "utils/lsyscache.h"
 | 
				
			||||||
@ -161,8 +162,8 @@ typedef struct avw_dbase
 | 
				
			|||||||
/* struct to keep track of tables to vacuum and/or analyze, in 1st pass */
 | 
					/* struct to keep track of tables to vacuum and/or analyze, in 1st pass */
 | 
				
			||||||
typedef struct av_relation
 | 
					typedef struct av_relation
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						Oid			ar_toastrelid;	/* hash key - must be first */
 | 
				
			||||||
	Oid			ar_relid;
 | 
						Oid			ar_relid;
 | 
				
			||||||
	Oid			ar_toastrelid;
 | 
					 | 
				
			||||||
} av_relation;
 | 
					} av_relation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
 | 
					/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
 | 
				
			||||||
@ -279,7 +280,7 @@ static void autovac_balance_cost(void);
 | 
				
			|||||||
static void do_autovacuum(void);
 | 
					static void do_autovacuum(void);
 | 
				
			||||||
static void FreeWorkerInfo(int code, Datum arg);
 | 
					static void FreeWorkerInfo(int code, Datum arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static autovac_table *table_recheck_autovac(Oid relid);
 | 
					static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map);
 | 
				
			||||||
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
 | 
					static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
 | 
				
			||||||
						  Form_pg_class classForm,
 | 
											  Form_pg_class classForm,
 | 
				
			||||||
						  PgStat_StatTabEntry *tabentry, bool *dovacuum,
 | 
											  PgStat_StatTabEntry *tabentry, bool *dovacuum,
 | 
				
			||||||
@ -287,7 +288,8 @@ static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void autovacuum_do_vac_analyze(autovac_table *tab,
 | 
					static void autovacuum_do_vac_analyze(autovac_table *tab,
 | 
				
			||||||
						  BufferAccessStrategy bstrategy);
 | 
											  BufferAccessStrategy bstrategy);
 | 
				
			||||||
static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid);
 | 
					static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
 | 
				
			||||||
 | 
																   HTAB *table_toast_map);
 | 
				
			||||||
static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
 | 
					static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
 | 
				
			||||||
						  PgStat_StatDBEntry *shared,
 | 
											  PgStat_StatDBEntry *shared,
 | 
				
			||||||
						  PgStat_StatDBEntry *dbentry);
 | 
											  PgStat_StatDBEntry *dbentry);
 | 
				
			||||||
@ -1821,12 +1823,13 @@ do_autovacuum(void)
 | 
				
			|||||||
	HeapScanDesc relScan;
 | 
						HeapScanDesc relScan;
 | 
				
			||||||
	Form_pg_database dbForm;
 | 
						Form_pg_database dbForm;
 | 
				
			||||||
	List	   *table_oids = NIL;
 | 
						List	   *table_oids = NIL;
 | 
				
			||||||
	List	   *toast_oids = NIL;
 | 
						HASHCTL		ctl;
 | 
				
			||||||
	List	   *table_toast_list = NIL;
 | 
						HTAB	   *table_toast_map;
 | 
				
			||||||
	ListCell   *volatile cell;
 | 
						ListCell   *volatile cell;
 | 
				
			||||||
	PgStat_StatDBEntry *shared;
 | 
						PgStat_StatDBEntry *shared;
 | 
				
			||||||
	PgStat_StatDBEntry *dbentry;
 | 
						PgStat_StatDBEntry *dbentry;
 | 
				
			||||||
	BufferAccessStrategy bstrategy;
 | 
						BufferAccessStrategy bstrategy;
 | 
				
			||||||
 | 
						ScanKeyData	key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * StartTransactionCommand and CommitTransactionCommand will automatically
 | 
						 * StartTransactionCommand and CommitTransactionCommand will automatically
 | 
				
			||||||
@ -1884,25 +1887,42 @@ do_autovacuum(void)
 | 
				
			|||||||
	classRel = heap_open(RelationRelationId, AccessShareLock);
 | 
						classRel = heap_open(RelationRelationId, AccessShareLock);
 | 
				
			||||||
	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
 | 
						avRel = heap_open(AutovacuumRelationId, AccessShareLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/* create hash table for toast <-> main relid mapping */
 | 
				
			||||||
	 * Scan pg_class and determine which tables to vacuum.
 | 
						MemSet(&ctl, 0, sizeof(ctl));
 | 
				
			||||||
	 *
 | 
						ctl.keysize = sizeof(Oid);
 | 
				
			||||||
	 * The stats subsystem collects stats for toast tables independently of
 | 
						ctl.entrysize = sizeof(Oid) * 2;
 | 
				
			||||||
	 * the stats for their parent tables.  We need to check those stats since
 | 
						ctl.hash = oid_hash;
 | 
				
			||||||
	 * 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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						table_toast_map = hash_create("TOAST to main relid map",
 | 
				
			||||||
 | 
													  100,
 | 
				
			||||||
 | 
													  &ctl,
 | 
				
			||||||
 | 
													  HASH_ELEM | HASH_FUNCTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * 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)
 | 
						while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
 | 
							Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
 | 
				
			||||||
@ -1915,15 +1935,10 @@ do_autovacuum(void)
 | 
				
			|||||||
		bool		wraparound;
 | 
							bool		wraparound;
 | 
				
			||||||
		int			backendID;
 | 
							int			backendID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Consider only regular and toast tables. */
 | 
					 | 
				
			||||||
		if (classForm->relkind != RELKIND_RELATION &&
 | 
					 | 
				
			||||||
			classForm->relkind != RELKIND_TOASTVALUE)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		relid = HeapTupleGetOid(tuple);
 | 
							relid = HeapTupleGetOid(tuple);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Fetch the pg_autovacuum tuple for the relation, if any */
 | 
							/* Fetch the pg_autovacuum tuple for the relation, if any */
 | 
				
			||||||
		avTup = get_pg_autovacuum_tuple_relid(avRel, relid);
 | 
							avTup = get_pg_autovacuum_tuple_relid(avRel, relid, NULL);
 | 
				
			||||||
		if (HeapTupleIsValid(avTup))
 | 
							if (HeapTupleIsValid(avTup))
 | 
				
			||||||
			avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
 | 
								avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1952,7 +1967,7 @@ do_autovacuum(void)
 | 
				
			|||||||
				 * vacuum for wraparound, forcibly drop it.  Otherwise just
 | 
									 * vacuum for wraparound, forcibly drop it.  Otherwise just
 | 
				
			||||||
				 * log a complaint.
 | 
									 * log a complaint.
 | 
				
			||||||
				 */
 | 
									 */
 | 
				
			||||||
				if (wraparound && classForm->relkind == RELKIND_RELATION)
 | 
									if (wraparound)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					ObjectAddress object;
 | 
										ObjectAddress object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1976,30 +1991,32 @@ do_autovacuum(void)
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (classForm->relkind == RELKIND_RELATION)
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			/* Plain relations that need work are added to table_oids */
 | 
								/* Plain relations that need work are added to table_oids */
 | 
				
			||||||
			if (dovacuum || doanalyze)
 | 
								if (dovacuum || doanalyze)
 | 
				
			||||||
				table_oids = lappend_oid(table_oids, relid);
 | 
									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
 | 
								 * Remember the association for the second pass.  Note: we must do
 | 
				
			||||||
				 * table, remember the association to revisit below.
 | 
								 * this even if the table is going to be vacuumed, because we
 | 
				
			||||||
 | 
								 * don't automatically vacuum toast tables along the parent table.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
				av_relation *rel = palloc(sizeof(av_relation));
 | 
								if (OidIsValid(classForm->reltoastrelid))
 | 
				
			||||||
 | 
					 | 
				
			||||||
				rel->ar_relid = relid;
 | 
					 | 
				
			||||||
				rel->ar_toastrelid = classForm->reltoastrelid;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				table_toast_list = lappend(table_toast_list, rel);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
			/* TOAST relations that need vacuum are added to toast_oids */
 | 
									av_relation *hentry;
 | 
				
			||||||
			if (dovacuum)
 | 
									bool		found;
 | 
				
			||||||
				toast_oids = lappend_oid(toast_oids, relid);
 | 
					
 | 
				
			||||||
 | 
									hentry = hash_search(table_toast_map,
 | 
				
			||||||
 | 
														 &classForm->reltoastrelid,
 | 
				
			||||||
 | 
														 HASH_ENTER, &found);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!found)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										/* hash_search already filled in the key */
 | 
				
			||||||
 | 
										hentry->ar_relid = relid;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (HeapTupleIsValid(avTup))
 | 
							if (HeapTupleIsValid(avTup))
 | 
				
			||||||
@ -2007,34 +2024,55 @@ do_autovacuum(void)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	heap_endscan(relScan);
 | 
						heap_endscan(relScan);
 | 
				
			||||||
	heap_close(avRel, AccessShareLock);
 | 
					
 | 
				
			||||||
	heap_close(classRel, AccessShareLock);
 | 
						/* 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
	 * Add to the list of tables to vacuum, the OIDs of the tables that
 | 
							 * Skip temp tables (i.e. those in temp namespaces).  We cannot safely
 | 
				
			||||||
	 * correspond to the saved OIDs of toast tables needing vacuum.
 | 
							 * process other backends' temp tables.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
	foreach(cell, toast_oids)
 | 
							if (isAnyTempNamespace(classForm->relnamespace))
 | 
				
			||||||
	{
 | 
								continue;
 | 
				
			||||||
		Oid			toastoid = lfirst_oid(cell);
 | 
					 | 
				
			||||||
		ListCell   *cell2;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		foreach(cell2, table_toast_list)
 | 
							relid = HeapTupleGetOid(tuple);
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			av_relation *ar = lfirst(cell2);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (ar->ar_toastrelid == toastoid)
 | 
							/* Fetch the pg_autovacuum tuple for this rel */
 | 
				
			||||||
			{
 | 
							avTup = get_pg_autovacuum_tuple_relid(avRel, relid, table_toast_map);
 | 
				
			||||||
				table_oids = lappend_oid(table_oids, ar->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);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_free_deep(table_toast_list);
 | 
						heap_endscan(relScan);
 | 
				
			||||||
	table_toast_list = NIL;
 | 
						heap_close(avRel, AccessShareLock);
 | 
				
			||||||
	list_free(toast_oids);
 | 
						heap_close(classRel, AccessShareLock);
 | 
				
			||||||
	toast_oids = NIL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Create a buffer access strategy object for VACUUM to use.  We want to
 | 
						 * Create a buffer access strategy object for VACUUM to use.  We want to
 | 
				
			||||||
@ -2118,7 +2156,7 @@ do_autovacuum(void)
 | 
				
			|||||||
		 * vacuumed in the last 500ms (PGSTAT_STAT_INTERVAL).  This is a bug.
 | 
							 * vacuumed in the last 500ms (PGSTAT_STAT_INTERVAL).  This is a bug.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		MemoryContextSwitchTo(AutovacMemCxt);
 | 
							MemoryContextSwitchTo(AutovacMemCxt);
 | 
				
			||||||
		tab = table_recheck_autovac(relid);
 | 
							tab = table_recheck_autovac(relid, table_toast_map);
 | 
				
			||||||
		if (tab == NULL)
 | 
							if (tab == NULL)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			/* someone else vacuumed the table */
 | 
								/* someone else vacuumed the table */
 | 
				
			||||||
@ -2231,6 +2269,11 @@ deleted:
 | 
				
			|||||||
		LWLockRelease(AutovacuumLock);
 | 
							LWLockRelease(AutovacuumLock);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We leak table_toast_map here (among other things), but since we're going
 | 
				
			||||||
 | 
						 * away soon, it's not a problem.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Update pg_database.datfrozenxid, and truncate pg_clog if possible. We
 | 
						 * Update pg_database.datfrozenxid, and truncate pg_clog if possible. We
 | 
				
			||||||
	 * only need to do this once, not after each table.
 | 
						 * only need to do this once, not after each table.
 | 
				
			||||||
@ -2244,9 +2287,14 @@ deleted:
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * Returns a copy of the pg_autovacuum tuple for the given relid, or NULL if
 | 
					 * Returns a copy of the pg_autovacuum tuple for the given relid, or NULL if
 | 
				
			||||||
 * there isn't any.  avRel is pg_autovacuum, already open and suitably locked.
 | 
					 * there isn't any.  avRel is pg_autovacuum, already open and suitably locked.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If table_toast_map is not null, use it to find an alternative OID with which
 | 
				
			||||||
 | 
					 * to search a pg_autovacuum entry, if the passed relid does not yield one
 | 
				
			||||||
 | 
					 * directly.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static HeapTuple
 | 
					static HeapTuple
 | 
				
			||||||
get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid)
 | 
					get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
 | 
				
			||||||
 | 
												  HTAB *table_toast_map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ScanKeyData entry[1];
 | 
						ScanKeyData entry[1];
 | 
				
			||||||
	SysScanDesc avScan;
 | 
						SysScanDesc avScan;
 | 
				
			||||||
@ -2267,6 +2315,18 @@ get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	systable_endscan(avScan);
 | 
						systable_endscan(avScan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!HeapTupleIsValid(avTup) && table_toast_map != NULL)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							av_relation		*hentry;
 | 
				
			||||||
 | 
							bool		found;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
 | 
				
			||||||
 | 
							if (found)
 | 
				
			||||||
 | 
								/* avoid second recursion */
 | 
				
			||||||
 | 
								avTup = get_pg_autovacuum_tuple_relid(avRel, hentry->ar_relid,
 | 
				
			||||||
 | 
																	  NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return avTup;
 | 
						return avTup;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2297,14 +2357,13 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared,
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * table_recheck_autovac
 | 
					 * table_recheck_autovac
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Recheck whether a plain table still needs vacuum or analyze; be it because
 | 
					 * Recheck whether a table still needs vacuum or analyze.  Return value is a
 | 
				
			||||||
 * it does directly, or because its TOAST table does.  Return value is a valid
 | 
					 * valid autovac_table pointer if it does, NULL otherwise.
 | 
				
			||||||
 * autovac_table pointer if it does, NULL otherwise.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Note that the returned autovac_table does not have the name fields set.
 | 
					 * Note that the returned autovac_table does not have the name fields set.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static autovac_table *
 | 
					static autovac_table *
 | 
				
			||||||
table_recheck_autovac(Oid relid)
 | 
					table_recheck_autovac(Oid relid, HTAB *table_toast_map)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Form_pg_autovacuum avForm = NULL;
 | 
						Form_pg_autovacuum avForm = NULL;
 | 
				
			||||||
	Form_pg_class classForm;
 | 
						Form_pg_class classForm;
 | 
				
			||||||
@ -2315,11 +2374,9 @@ table_recheck_autovac(Oid relid)
 | 
				
			|||||||
	bool		doanalyze;
 | 
						bool		doanalyze;
 | 
				
			||||||
	autovac_table *tab = NULL;
 | 
						autovac_table *tab = NULL;
 | 
				
			||||||
	PgStat_StatTabEntry *tabentry;
 | 
						PgStat_StatTabEntry *tabentry;
 | 
				
			||||||
	bool		doit = false;
 | 
					 | 
				
			||||||
	PgStat_StatDBEntry *shared;
 | 
						PgStat_StatDBEntry *shared;
 | 
				
			||||||
	PgStat_StatDBEntry *dbentry;
 | 
						PgStat_StatDBEntry *dbentry;
 | 
				
			||||||
	bool		wraparound,
 | 
						bool		wraparound;
 | 
				
			||||||
				toast_wraparound = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* use fresh stats */
 | 
						/* use fresh stats */
 | 
				
			||||||
	autovac_refresh_stats();
 | 
						autovac_refresh_stats();
 | 
				
			||||||
@ -2335,9 +2392,15 @@ table_recheck_autovac(Oid relid)
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	classForm = (Form_pg_class) GETSTRUCT(classTup);
 | 
						classForm = (Form_pg_class) GETSTRUCT(classTup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* fetch the pg_autovacuum entry, if any */
 | 
						/*
 | 
				
			||||||
 | 
						 * 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);
 | 
						avRel = heap_open(AutovacuumRelationId, AccessShareLock);
 | 
				
			||||||
	avTup = get_pg_autovacuum_tuple_relid(avRel, relid);
 | 
						avTup = get_pg_autovacuum_tuple_relid(avRel, relid,
 | 
				
			||||||
 | 
								classForm->relkind == RELKIND_TOASTVALUE ? table_toast_map : NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (HeapTupleIsValid(avTup))
 | 
						if (HeapTupleIsValid(avTup))
 | 
				
			||||||
		avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
 | 
							avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2348,51 +2411,12 @@ table_recheck_autovac(Oid relid)
 | 
				
			|||||||
	relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
 | 
						relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
 | 
				
			||||||
							  &dovacuum, &doanalyze, &wraparound);
 | 
												  &dovacuum, &doanalyze, &wraparound);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* OK, it needs vacuum by itself */
 | 
						/* ignore ANALYZE for toast tables */
 | 
				
			||||||
	if (dovacuum)
 | 
						if (classForm->relkind == RELKIND_TOASTVALUE)
 | 
				
			||||||
		doit = true;
 | 
							doanalyze = false;
 | 
				
			||||||
	/* 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,
 | 
						/* OK, it needs something done */
 | 
				
			||||||
										   ObjectIdGetDatum(toastrelid),
 | 
						if (doanalyze || dovacuum)
 | 
				
			||||||
										   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			freeze_min_age;
 | 
				
			||||||
		int			vac_cost_limit;
 | 
							int			vac_cost_limit;
 | 
				
			||||||
@ -2439,7 +2463,7 @@ table_recheck_autovac(Oid relid)
 | 
				
			|||||||
		tab->at_freeze_min_age = freeze_min_age;
 | 
							tab->at_freeze_min_age = freeze_min_age;
 | 
				
			||||||
		tab->at_vacuum_cost_limit = vac_cost_limit;
 | 
							tab->at_vacuum_cost_limit = vac_cost_limit;
 | 
				
			||||||
		tab->at_vacuum_cost_delay = vac_cost_delay;
 | 
							tab->at_vacuum_cost_delay = vac_cost_delay;
 | 
				
			||||||
		tab->at_wraparound = wraparound || toast_wraparound;
 | 
							tab->at_wraparound = wraparound;
 | 
				
			||||||
		tab->at_relname = NULL;
 | 
							tab->at_relname = NULL;
 | 
				
			||||||
		tab->at_nspname = NULL;
 | 
							tab->at_nspname = NULL;
 | 
				
			||||||
		tab->at_datname = NULL;
 | 
							tab->at_datname = NULL;
 | 
				
			||||||
@ -2633,7 +2657,7 @@ autovacuum_do_vac_analyze(autovac_table *tab,
 | 
				
			|||||||
	/* Let pgstat know what we're doing */
 | 
						/* Let pgstat know what we're doing */
 | 
				
			||||||
	autovac_report_activity(tab);
 | 
						autovac_report_activity(tab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vacuum(&vacstmt, tab->at_relid, bstrategy, tab->at_wraparound, true);
 | 
						vacuum(&vacstmt, tab->at_relid, false, bstrategy, tab->at_wraparound, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.295 2008/07/18 20:26:06 tgl Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.296 2008/08/13 00:07:50 alvherre Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -836,7 +836,7 @@ ProcessUtility(Node *parsetree,
 | 
				
			|||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case T_VacuumStmt:
 | 
							case T_VacuumStmt:
 | 
				
			||||||
			vacuum((VacuumStmt *) parsetree, InvalidOid, NULL, false,
 | 
								vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false,
 | 
				
			||||||
				   isTopLevel);
 | 
									   isTopLevel);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@
 | 
				
			|||||||
 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
 | 
					 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
 | 
				
			||||||
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
					 * Portions Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.79 2008/07/01 10:33:09 heikki Exp $
 | 
					 * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.80 2008/08/13 00:07:50 alvherre Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -125,7 +125,7 @@ extern int	vacuum_freeze_min_age;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* in commands/vacuum.c */
 | 
					/* in commands/vacuum.c */
 | 
				
			||||||
extern void vacuum(VacuumStmt *vacstmt, Oid relid,
 | 
					extern void vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
 | 
				
			||||||
	   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel);
 | 
						   BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel);
 | 
				
			||||||
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
 | 
					extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
 | 
				
			||||||
				 int *nindexes, Relation **Irel);
 | 
									 int *nindexes, Relation **Irel);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user