diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/common/reloptions.c | 106 | ||||
-rw-r--r-- | src/backend/catalog/Makefile | 4 | ||||
-rw-r--r-- | src/backend/postmaster/autovacuum.c | 279 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 4 | ||||
-rw-r--r-- | src/include/catalog/indexing.h | 5 | ||||
-rw-r--r-- | src/include/catalog/pg_autovacuum.h | 66 | ||||
-rw-r--r-- | src/include/utils/rel.h | 18 | ||||
-rw-r--r-- | src/test/regress/expected/sanity_check.out | 3 |
8 files changed, 253 insertions, 232 deletions
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index e566a136442..548c0b00de8 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -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); diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 58973c9a889..9a828d66fe1 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -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 \ diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index ed77c51c9ff..e7aea7fc23c 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -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); - - 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); - } + 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); - 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; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 1db49f6a152..d02bde48c82 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 1c517c7f3b6..bb5b9eabf63 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -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)); diff --git a/src/include/catalog/pg_autovacuum.h b/src/include/catalog/pg_autovacuum.h deleted file mode 100644 index 94eb05b9250..00000000000 --- a/src/include/catalog/pg_autovacuum.h +++ /dev/null @@ -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 */ diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index ffb2b8530d3..a3aaf69e2f1 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -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 diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index e677d4580fd..c6f1f158ee5 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -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 |