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:
Alvaro Herrera 2008-08-13 00:07:50 +00:00
parent 010eebf164
commit 3ccde312ec
4 changed files with 176 additions and 145 deletions

View File

@ -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,8 +213,8 @@ 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,
VacPageList vacuum_pages, VacPageList fraged_pages); VacPageList vacuum_pages, VacPageList fraged_pages);
@ -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.
*/ */
toast_relid = onerel->rd_rel->reltoastrelid; 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 * 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.

View File

@ -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,65 +1991,88 @@ 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))
/*
* 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.
*/
if (OidIsValid(classForm->reltoastrelid))
{ {
/* av_relation *hentry;
* If it doesn't appear to need vacuuming, but it has a toast bool found;
* table, remember the association to revisit below.
*/
av_relation *rel = palloc(sizeof(av_relation));
rel->ar_relid = relid; hentry = hash_search(table_toast_map,
rel->ar_toastrelid = classForm->reltoastrelid; &classForm->reltoastrelid,
HASH_ENTER, &found);
table_toast_list = lappend(table_toast_list, rel); if (!found)
{
/* hash_search already filled in the key */
hentry->ar_relid = relid;
}
} }
} }
else
{
/* TOAST relations that need vacuum are added to toast_oids */
if (dovacuum)
toast_oids = lappend_oid(toast_oids, relid);
}
if (HeapTupleIsValid(avTup)) if (HeapTupleIsValid(avTup))
heap_freetuple(avTup); heap_freetuple(avTup);
} }
heap_endscan(relScan); heap_endscan(relScan);
heap_close(avRel, AccessShareLock);
heap_close(classRel, AccessShareLock);
/* /* second pass: check TOAST tables */
* Add to the list of tables to vacuum, the OIDs of the tables that ScanKeyInit(&key,
* correspond to the saved OIDs of toast tables needing vacuum. Anum_pg_class_relkind,
*/ BTEqualStrategyNumber, F_CHAREQ,
foreach(cell, toast_oids) CharGetDatum(RELKIND_TOASTVALUE));
relScan = heap_beginscan(classRel, SnapshotNow, 1, &key);
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{ {
Oid toastoid = lfirst_oid(cell); Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
ListCell *cell2; Form_pg_autovacuum avForm = NULL;
PgStat_StatTabEntry *tabentry;
HeapTuple avTup;
Oid relid;
bool dovacuum;
bool doanalyze;
bool wraparound;
foreach(cell2, table_toast_list) /*
{ * Skip temp tables (i.e. those in temp namespaces). We cannot safely
av_relation *ar = lfirst(cell2); * process other backends' temp tables.
*/
if (isAnyTempNamespace(classForm->relnamespace))
continue;
if (ar->ar_toastrelid == toastoid) relid = HeapTupleGetOid(tuple);
{
table_oids = lappend_oid(table_oids, ar->ar_relid); /* Fetch the pg_autovacuum tuple for this rel */
break; avTup = get_pg_autovacuum_tuple_relid(avRel, relid, table_toast_map);
}
} 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);
} }
/* /*

View File

@ -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;

View File

@ -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);