1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Update autovacuum to use reloptions instead of a system catalog, for

per-table overrides of parameters.

This removes a whole class of problems related to misusing the catalog,
and perhaps more importantly, gives us pg_dump support for the parameters.

Based on a patch by Euler Taveira de Oliveira, heavily reworked by me.
This commit is contained in:
Alvaro Herrera
2009-02-09 20:57:59 +00:00
parent 57b10ebcd4
commit 834a6da4f7
13 changed files with 421 additions and 483 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.20 2009/02/02 19:31:38 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.21 2009/02/09 20:57:59 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@ -48,6 +48,14 @@
static relopt_bool boolRelOpts[] =
{
{
{
"autovacuum_enabled",
"Enables autovacuum in this relation",
RELOPT_KIND_HEAP
},
true
},
/* list terminator */
{ { NULL } }
};
@ -86,12 +94,83 @@ static relopt_int intRelOpts[] =
},
GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
},
{
{
"autovacuum_vacuum_threshold",
"Minimum number of tuple updates or deletes prior to vacuum",
RELOPT_KIND_HEAP
},
50, 0, INT_MAX
},
{
{
"autovacuum_analyze_threshold",
"Minimum number of tuple inserts, updates or deletes prior to analyze",
RELOPT_KIND_HEAP
},
50, 0, INT_MAX
},
{
{
"autovacuum_vacuum_cost_delay",
"Vacuum cost delay in milliseconds, for autovacuum",
RELOPT_KIND_HEAP
},
20, 0, 1000
},
{
{
"autovacuum_vacuum_cost_limit",
"Vacuum cost amount available before napping, for autovacuum",
RELOPT_KIND_HEAP
},
200, 1, 10000
},
{
{
"autovacuum_freeze_min_age",
"Minimum age at which VACUUM should freeze a table row, for autovacuum",
RELOPT_KIND_HEAP
},
100000000, 0, 1000000000
},
{
{
"autovacuum_freeze_max_age",
"Age at which to autovacuum a table to prevent transaction ID wraparound",
RELOPT_KIND_HEAP
},
200000000, 100000000, 2000000000
},
{
{
"autovacuum_freeze_table_age",
"Age at which VACUUM should perform a full table sweep to replace old Xid values with FrozenXID",
RELOPT_KIND_HEAP
}, 150000000, 0, 2000000000
},
/* list terminator */
{ { NULL } }
};
static relopt_real realRelOpts[] =
{
{
{
"autovacuum_vacuum_scale_factor",
"Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
RELOPT_KIND_HEAP
},
0.2, 0.0, 100.0
},
{
{
"autovacuum_analyze_scale_factor",
"Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
RELOPT_KIND_HEAP
},
0.1, 0.0, 100.0
},
/* list terminator */
{ { NULL } }
};
@ -973,7 +1052,8 @@ fillRelOptions(void *rdopts, Size basesize, relopt_value *options,
/*
* Option parser for anything that uses StdRdOptions (i.e. fillfactor only)
* Option parser for anything that uses StdRdOptions (i.e. fillfactor and
* autovacuum)
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
@ -982,7 +1062,27 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
StdRdOptions *rdopts;
int numoptions;
relopt_parse_elt tab[] = {
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);

View File

@ -2,7 +2,7 @@
#
# Makefile for backend/catalog
#
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.68 2008/12/19 16:25:16 petere Exp $
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.69 2009/02/09 20:57:59 alvherre Exp $
#
#-------------------------------------------------------------------------
@ -26,7 +26,7 @@ all: $(BKIFILES)
# indexing.h had better be last, and toasting.h just before it.
POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
pg_proc.h pg_type.h pg_attribute.h pg_class.h \
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \

View File

@ -55,7 +55,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.92 2009/01/16 13:27:24 heikki Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.93 2009/02/09 20:57:59 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@ -69,12 +69,12 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "access/reloptions.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_autovacuum.h"
#include "catalog/pg_database.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
@ -165,13 +165,15 @@ typedef struct av_relation
{
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
bool ar_hasrelopts;
AutoVacOpts ar_reloptions; /* copy of AutoVacOpts from the main table's
reloptions, or NULL if none */
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
typedef struct autovac_table
{
Oid at_relid;
Oid at_toastrelid;
bool at_dovacuum;
bool at_doanalyze;
int at_freeze_min_age;
@ -282,16 +284,17 @@ static void autovac_balance_cost(void);
static void do_autovacuum(void);
static void FreeWorkerInfo(int code, Datum arg);
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map);
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc);
static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry, bool *dovacuum,
bool *doanalyze, bool *wraparound);
PgStat_StatTabEntry *tabentry,
bool *dovacuum, bool *doanalyze, bool *wraparound);
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
HTAB *table_toast_map);
static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
TupleDesc pg_class_desc);
static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
PgStat_StatDBEntry *shared,
PgStat_StatDBEntry *dbentry);
@ -1816,8 +1819,7 @@ get_database_list(void)
static void
do_autovacuum(void)
{
Relation classRel,
avRel;
Relation classRel;
HeapTuple tuple;
HeapScanDesc relScan;
Form_pg_database dbForm;
@ -1829,6 +1831,7 @@ do_autovacuum(void)
PgStat_StatDBEntry *dbentry;
BufferAccessStrategy bstrategy;
ScanKeyData key;
TupleDesc pg_class_desc;
/*
* StartTransactionCommand and CommitTransactionCommand will automatically
@ -1890,12 +1893,14 @@ do_autovacuum(void)
shared = pgstat_fetch_stat_dbentry(InvalidOid);
classRel = heap_open(RelationRelationId, AccessShareLock);
avRel = heap_open(AutovacuumRelationId, AccessShareLock);
/* create a copy so we can use it after closing pg_class */
pg_class_desc = CreateTupleDescCopy(RelationGetDescr(classRel));
/* create hash table for toast <-> main relid mapping */
MemSet(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(Oid);
ctl.entrysize = sizeof(Oid) * 2;
ctl.entrysize = sizeof(av_relation);
ctl.hash = oid_hash;
table_toast_map = hash_create("TOAST to main relid map",
@ -1909,9 +1914,9 @@ do_autovacuum(void)
* 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.
* the main relation's pg_class.reloptions 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
@ -1931,9 +1936,8 @@ do_autovacuum(void)
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;
AutoVacOpts *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
@ -1942,17 +1946,13 @@ do_autovacuum(void)
relid = HeapTupleGetOid(tuple);
/* Fetch the pg_autovacuum tuple for the relation, if any */
avTup = get_pg_autovacuum_tuple_relid(avRel, relid, NULL);
if (HeapTupleIsValid(avTup))
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
/* Fetch the pgstat entry for this table */
/* Fetch reloptions and the pgstat entry for this table */
relopts = extract_autovac_opts(tuple, pg_class_desc);
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
shared, dbentry);
/* Check if it needs vacuum or analyze */
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/*
@ -1998,7 +1998,7 @@ do_autovacuum(void)
}
else
{
/* Plain relations that need work are added to table_oids */
/* relations that need work are added to table_oids */
if (dovacuum || doanalyze)
table_oids = lappend_oid(table_oids, relid);
@ -2020,12 +2020,16 @@ do_autovacuum(void)
{
/* hash_search already filled in the key */
hentry->ar_relid = relid;
hentry->ar_hasrelopts = false;
if (relopts != NULL)
{
hentry->ar_hasrelopts = true;
memcpy(&hentry->ar_reloptions, relopts,
sizeof(AutoVacOpts));
}
}
}
}
if (HeapTupleIsValid(avTup))
heap_freetuple(avTup);
}
heap_endscan(relScan);
@ -2040,10 +2044,9 @@ do_autovacuum(void)
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;
AutoVacOpts *relopts = NULL;
bool dovacuum;
bool doanalyze;
bool wraparound;
@ -2057,17 +2060,26 @@ do_autovacuum(void)
relid = HeapTupleGetOid(tuple);
/* Fetch the pg_autovacuum tuple for this rel */
avTup = get_pg_autovacuum_tuple_relid(avRel, relid, table_toast_map);
/*
* fetch reloptions -- if this toast table does not have them,
* try the main rel
*/
relopts = extract_autovac_opts(tuple, pg_class_desc);
if (relopts == NULL)
{
av_relation *hentry;
bool found;
if (HeapTupleIsValid(avTup))
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
relopts = &hentry->ar_reloptions;
}
/* Fetch the pgstat entry for this table */
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
shared, dbentry);
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/* ignore analyze for toast tables */
@ -2076,7 +2088,6 @@ do_autovacuum(void)
}
heap_endscan(relScan);
heap_close(avRel, AccessShareLock);
heap_close(classRel, AccessShareLock);
/*
@ -2163,10 +2174,10 @@ do_autovacuum(void)
* condition is not closed but it is very small.
*/
MemoryContextSwitchTo(AutovacMemCxt);
tab = table_recheck_autovac(relid, table_toast_map);
tab = table_recheck_autovac(relid, table_toast_map, pg_class_desc);
if (tab == NULL)
{
/* someone else vacuumed the table */
/* someone else vacuumed the table, or it went away */
LWLockRelease(AutovacuumScheduleLock);
continue;
}
@ -2292,49 +2303,29 @@ deleted:
}
/*
* 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.
* extract_autovac_opts
*
* 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.
* Given a relation's pg_class tuple, return the AutoVacOpts portion of
* reloptions, if set; otherwise, return NULL.
*/
static HeapTuple
get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
HTAB *table_toast_map)
AutoVacOpts *
extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
{
ScanKeyData entry[1];
SysScanDesc avScan;
HeapTuple avTup;
bytea *relopts;
AutoVacOpts *av;
ScanKeyInit(&entry[0],
Anum_pg_autovacuum_vacrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relid));
Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true,
SnapshotNow, 1, entry);
relopts = extractRelOptions(tup, pg_class_desc, InvalidOid);
if (relopts == NULL)
return NULL;
av = palloc(sizeof(AutoVacOpts));
memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
pfree(relopts);
avTup = systable_getnext(avScan);
if (HeapTupleIsValid(avTup))
avTup = heap_copytuple(avTup);
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 av;
}
/*
@ -2370,13 +2361,11 @@ get_pgstat_tabentry_relid(Oid relid, bool isshared, PgStat_StatDBEntry *shared,
* Note that the returned autovac_table does not have the name fields set.
*/
static autovac_table *
table_recheck_autovac(Oid relid, HTAB *table_toast_map)
table_recheck_autovac(Oid relid, HTAB *table_toast_map,
TupleDesc pg_class_desc)
{
Form_pg_autovacuum avForm = NULL;
Form_pg_class classForm;
HeapTuple classTup;
HeapTuple avTup;
Relation avRel;
bool dovacuum;
bool doanalyze;
autovac_table *tab = NULL;
@ -2384,6 +2373,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map)
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
bool wraparound;
AutoVacOpts *avopts;
/* use fresh stats */
autovac_refresh_stats();
@ -2399,23 +2389,27 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map)
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.
/*
* Get the applicable reloptions. If it is a TOAST table, try to get the
* main table reloptions if the toast table itself doesn't have.
*/
avRel = heap_open(AutovacuumRelationId, AccessShareLock);
avTup = get_pg_autovacuum_tuple_relid(avRel, relid,
classForm->relkind == RELKIND_TOASTVALUE ? table_toast_map : NULL);
avopts = extract_autovac_opts(classTup, pg_class_desc);
if (classForm->relkind == RELKIND_TOASTVALUE &&
avopts == NULL && table_toast_map != NULL)
{
av_relation *hentry;
bool found;
if (HeapTupleIsValid(avTup))
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
if (found && hentry->ar_hasrelopts)
avopts = &hentry->ar_reloptions;
}
/* fetch the pgstat table entry */
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
shared, dbentry);
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/* ignore ANALYZE for toast tables */
@ -2431,41 +2425,28 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map)
int vac_cost_delay;
/*
* Calculate the vacuum cost parameters and the minimum freeze age. If
* there is a tuple in pg_autovacuum, use it; else, use the GUC
* defaults. Note that the fields may contain "-1" (or indeed any
* negative value), which means use the GUC defaults for each setting.
* In cost_limit, the value 0 also means to use the value from
* elsewhere.
* Calculate the vacuum cost parameters and the freeze ages. If there
* are options set in pg_class.reloptions, use them; in the case of a
* toast table, try the main table too. Otherwise use the GUC
* defaults, autovacuum's own first and plain vacuum second.
*/
if (avForm != NULL)
if (avopts)
{
vac_cost_limit = (avForm->vac_cost_limit > 0) ?
avForm->vac_cost_limit :
((autovacuum_vac_cost_limit > 0) ?
autovacuum_vac_cost_limit : VacuumCostLimit);
vac_cost_delay = (avForm->vac_cost_delay >= 0) ?
avForm->vac_cost_delay :
((autovacuum_vac_cost_delay >= 0) ?
autovacuum_vac_cost_delay : VacuumCostDelay);
freeze_min_age = (avForm->freeze_min_age >= 0) ?
avForm->freeze_min_age : default_freeze_min_age;
freeze_table_age = (avForm->freeze_table_age >= 0) ?
avForm->freeze_table_age : default_freeze_table_age;
vac_cost_delay = avopts->vacuum_cost_delay;
vac_cost_limit = avopts->vacuum_cost_limit;
freeze_min_age = avopts->freeze_min_age;
freeze_table_age = avopts->freeze_table_age;
}
else
{
vac_cost_limit = (autovacuum_vac_cost_limit > 0) ?
autovacuum_vac_cost_limit : VacuumCostLimit;
vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
/* -1 in autovac setting means use plain vacuum_cost_delay */
vac_cost_delay = autovacuum_vac_cost_delay >= 0 ?
autovacuum_vac_cost_delay : VacuumCostDelay;
/* 0 or -1 in autovac setting means use plain vacuum_cost_limit */
vac_cost_limit = autovacuum_vac_cost_limit > 0 ?
autovacuum_vac_cost_limit : VacuumCostLimit;
/* these do not have autovacuum-specific settings */
freeze_min_age = default_freeze_min_age;
freeze_table_age = default_freeze_table_age;
}
@ -2483,9 +2464,6 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map)
tab->at_datname = NULL;
}
heap_close(avRel, AccessShareLock);
if (HeapTupleIsValid(avTup))
heap_freetuple(avTup);
heap_freetuple(classTup);
return tab;
@ -2496,8 +2474,12 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map)
*
* Check whether a relation needs to be vacuumed or analyzed; return each into
* "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
* being forced because of Xid wraparound. avForm and tabentry can be NULL,
* classForm shouldn't.
* being forced because of Xid wraparound.
*
* relopts is a pointer to the AutoVacOpts options (either for itself in the
* case of a plain table, or for either itself or its parent table in the case
* of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
* NULL.
*
* A table needs to be vacuumed if the number of dead tuples exceeds a
* threshold. This threshold is calculated as
@ -2513,19 +2495,19 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map)
* We also force vacuum if the table's relfrozenxid is more than freeze_max_age
* transactions back.
*
* A table whose pg_autovacuum.enabled value is false, is automatically
* skipped (unless we have to vacuum it due to freeze_max_age). Thus
* autovacuum can be disabled for specific tables. Also, when the stats
* A table whose autovacuum_enabled option is false is
* automatically skipped (unless we have to vacuum it due to freeze_max_age).
* Thus autovacuum can be disabled for specific tables. Also, when the stats
* collector does not have data about a table, it will be skipped.
*
* A table whose vac_base_thresh value is <0 takes the base value from the
* A table whose vac_base_thresh value is < 0 takes the base value from the
* autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor
* value <0 is substituted with the value of
* value < 0 is substituted with the value of
* autovacuum_vacuum_scale_factor GUC variable. Ditto for analyze.
*/
static void
relation_needs_vacanalyze(Oid relid,
Form_pg_autovacuum avForm,
AutoVacOpts *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
/* output params below */
@ -2534,9 +2516,10 @@ relation_needs_vacanalyze(Oid relid,
bool *wraparound)
{
bool force_vacuum;
bool av_enabled;
float4 reltuples; /* pg_class.reltuples */
/* constants from pg_autovacuum or GUC variables */
/* constants from reloptions or GUC variables */
int vac_base_thresh,
anl_base_thresh;
float4 vac_scale_factor,
@ -2558,36 +2541,28 @@ relation_needs_vacanalyze(Oid relid,
AssertArg(OidIsValid(relid));
/*
* Determine vacuum/analyze equation parameters. If there is a tuple in
* pg_autovacuum, use it; else, use the GUC defaults. Note that the
* fields may contain "-1" (or indeed any negative value), which means use
* the GUC defaults for each setting.
* Determine vacuum/analyze equation parameters. We have two possible
* sources: the passed reloptions (which could be a main table or a toast
* table), or the autovacuum GUC variables.
*/
if (avForm != NULL)
if (relopts)
{
vac_scale_factor = (avForm->vac_scale_factor >= 0) ?
avForm->vac_scale_factor : autovacuum_vac_scale;
vac_base_thresh = (avForm->vac_base_thresh >= 0) ?
avForm->vac_base_thresh : autovacuum_vac_thresh;
anl_scale_factor = (avForm->anl_scale_factor >= 0) ?
avForm->anl_scale_factor : autovacuum_anl_scale;
anl_base_thresh = (avForm->anl_base_thresh >= 0) ?
avForm->anl_base_thresh : autovacuum_anl_thresh;
freeze_max_age = (avForm->freeze_max_age >= 0) ?
Min(avForm->freeze_max_age, autovacuum_freeze_max_age) :
autovacuum_freeze_max_age;
vac_scale_factor = relopts->vacuum_scale_factor;
vac_base_thresh = relopts->vacuum_threshold;
anl_scale_factor = relopts->analyze_scale_factor;
anl_base_thresh = relopts->analyze_threshold;
freeze_max_age = Min(relopts->freeze_max_age,
autovacuum_freeze_max_age);
av_enabled = relopts->enabled;
}
else
{
vac_scale_factor = autovacuum_vac_scale;
vac_base_thresh = autovacuum_vac_thresh;
anl_scale_factor = autovacuum_anl_scale;
anl_base_thresh = autovacuum_anl_thresh;
freeze_max_age = autovacuum_freeze_max_age;
av_enabled = true;
}
/* Force vacuum if table is at risk of wraparound */
@ -2599,8 +2574,8 @@ relation_needs_vacanalyze(Oid relid,
xidForceLimit));
*wraparound = force_vacuum;
/* User disabled it in pg_autovacuum? (But ignore if at risk) */
if (avForm && !avForm->enabled && !force_vacuum)
/* User disabled it in pg_class.reloptions? (But ignore if at risk) */
if (!force_vacuum && !av_enabled)
{
*doanalyze = false;
*dovacuum = false;

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.521 2009/02/06 21:15:11 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.522 2009/02/09 20:57:59 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200902061
#define CATALOG_VERSION_NO 200902091
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.106 2009/01/22 20:16:08 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.107 2009/02/09 20:57:59 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@ -97,9 +97,6 @@ DECLARE_UNIQUE_INDEX(pg_auth_members_role_member_index, 2694, on pg_auth_members
DECLARE_UNIQUE_INDEX(pg_auth_members_member_role_index, 2695, on pg_auth_members using btree(member oid_ops, roleid oid_ops));
#define AuthMemMemRoleIndexId 2695
DECLARE_UNIQUE_INDEX(pg_autovacuum_vacrelid_index, 1250, on pg_autovacuum using btree(vacrelid oid_ops));
#define AutovacuumRelidIndexId 1250
DECLARE_UNIQUE_INDEX(pg_cast_oid_index, 2660, on pg_cast using btree(oid oid_ops));
#define CastOidIndexId 2660
DECLARE_UNIQUE_INDEX(pg_cast_source_target_index, 2661, on pg_cast using btree(castsource oid_ops, casttarget oid_ops));

View File

@ -1,66 +0,0 @@
/*-------------------------------------------------------------------------
*
* pg_autovacuum.h
* definition of the system "autovacuum" relation (pg_autovacuum)
*
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_autovacuum.h,v 1.11 2009/01/16 13:27:24 heikki Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PG_AUTOVACUUM_H
#define PG_AUTOVACUUM_H
#include "catalog/genbki.h"
/* ----------------
* pg_autovacuum definition. cpp turns this into
* typedef struct FormData_pg_autovacuum
* ----------------
*/
#define AutovacuumRelationId 1248
CATALOG(pg_autovacuum,1248) BKI_WITHOUT_OIDS
{
Oid vacrelid; /* OID of table */
bool enabled; /* enabled for this table? */
int4 vac_base_thresh; /* base threshold value */
float4 vac_scale_factor; /* reltuples scaling factor */
int4 anl_base_thresh; /* base threshold value */
float4 anl_scale_factor; /* reltuples scaling factor */
int4 vac_cost_delay; /* vacuum cost-based delay */
int4 vac_cost_limit; /* vacuum cost limit */
int4 freeze_min_age; /* vacuum min freeze age */
int4 freeze_max_age; /* max age before forcing vacuum */
int4 freeze_table_age; /* age at which vacuum scans whole table */
} FormData_pg_autovacuum;
/* ----------------
* Form_pg_autovacuum corresponds to a pointer to a tuple with
* the format of pg_autovacuum relation.
* ----------------
*/
typedef FormData_pg_autovacuum *Form_pg_autovacuum;
/* ----------------
* compiler constants for pg_autovacuum
* ----------------
*/
#define Natts_pg_autovacuum 10
#define Anum_pg_autovacuum_vacrelid 1
#define Anum_pg_autovacuum_enabled 2
#define Anum_pg_autovacuum_vac_base_thresh 3
#define Anum_pg_autovacuum_vac_scale_factor 4
#define Anum_pg_autovacuum_anl_base_thresh 5
#define Anum_pg_autovacuum_anl_scale_factor 6
#define Anum_pg_autovacuum_vac_cost_delay 7
#define Anum_pg_autovacuum_vac_cost_limit 8
#define Anum_pg_autovacuum_freeze_min_age 9
#define Anum_pg_autovacuum_freeze_max_age 10
#define Anum_pg_autovacuum_freeze_table_age 11
/* There are no preloaded tuples in pg_autovacuum.h */
#endif /* PG_AUTOVACUUM_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.111 2009/01/01 17:24:02 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.112 2009/02/09 20:57:59 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@ -214,10 +214,26 @@ typedef struct RelationData
* be applied to relations that use this format or a superset for
* private options data.
*/
/* autovacuum-related reloptions. */
typedef struct AutoVacOpts
{
bool enabled;
int vacuum_threshold;
int analyze_threshold;
int vacuum_cost_delay;
int vacuum_cost_limit;
int freeze_min_age;
int freeze_max_age;
int freeze_table_age;
float8 vacuum_scale_factor;
float8 analyze_scale_factor;
} AutoVacOpts;
typedef struct StdRdOptions
{
int32 vl_len_; /* varlena header (do not touch directly!) */
int fillfactor; /* page fill factor in percent (0..100) */
AutoVacOpts autovacuum; /* autovacuum-related options */
} StdRdOptions;
#define HEAP_MIN_FILLFACTOR 10

View File

@ -90,7 +90,6 @@ SELECT relname, relhasindex
pg_attribute | t
pg_auth_members | t
pg_authid | t
pg_autovacuum | t
pg_cast | t
pg_class | t
pg_constraint | t
@ -152,7 +151,7 @@ SELECT relname, relhasindex
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
(141 rows)
(140 rows)
--
-- another sanity check: every system catalog that has OIDs should have