autovacuum and reloptions
So I gave up waiting for someone else to do the reloptions patch for
autovacuum and started work on it myself. What I soon discovered is
that on first blush it seems a lot easier than I had expected.
On second look, however, the problem is that I seem to be
forced to declare all the autovacuum-related options and their parsing
properties in reloptions.c. This seems very ugly. I'd very much prefer
to be able to declare the options in autovacuum.c and let the rest of
the code just ignore them.
However, parseRelOptions seems inclined to barf about options it doesn't
know about. Maybe that's fine with the current usage, but I think it
would be better to leave the options in StdRdOptions alone, and have the
autovacuum options defined elsewhere, which seems to require an API
change to parseRelOptions -- though I'm not sure what's appropriate.
AFAICS this is completely uncharted territory -- the current code
understands only fillfactor as a valid option. If we were down the
route of just adding the new options just like fillfactor is currently
dealt with, the API would get really ugly very quickly.
It seems to me we should provide a way to "register" valid options, so
that autovacuum.c could inform reloptions.c what are the valid keys that
a normal option parsing should just ignore (and, conversely, what
options should it ignore when parsing for autovacuum). Thinking more
about it, it seems to me that the treatment that fillfactor currently
gets should be ripped out in favor of being registered too, somehow ...
Before we waste too much time thinking how this registering is to be
done, does anybody think that the current approach is OK and thus I
should just add the autovacuum options directly into StdRdOptions and
default_reloptions?
--
Alvaro Herrera Developer, http://www.PostgreSQL.org/
"El Maquinismo fue proscrito so pena de cosquilleo hasta la muerte"
(Ijon Tichy en Viajes, Stanislaw Lem)
Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
On second look, however, the problem is that I seem to be
forced to declare all the autovacuum-related options and their parsing
properties in reloptions.c. This seems very ugly.
That was in fact the intended design, and is why the functions exist in
a separate file reloptions.c rather than having been dumped into some
existing place like heapam.c. I don't see anything very wrong with
having autovacuum options in StdRdOptions and default_reloptions().
There might at some point be a good case for inventing a plugin approach
here, but since autovacuum is a pretty much core component now, I don't
see the need to do so for it.
regards, tom lane
Tom Lane wrote:
Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
On second look, however, the problem is that I seem to be
forced to declare all the autovacuum-related options and their parsing
properties in reloptions.c. This seems very ugly.That was in fact the intended design, and is why the functions exist in
a separate file reloptions.c rather than having been dumped into some
existing place like heapam.c. I don't see anything very wrong with
having autovacuum options in StdRdOptions and default_reloptions().
Hmm, OK. However, given that the various AMs amoptions also use
default_reloptions, they are going to accept the autovacuum options too.
Is that OK?
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Alvaro Herrera <alvherre@commandprompt.com> writes:
Hmm, OK. However, given that the various AMs amoptions also use
default_reloptions, they are going to accept the autovacuum options too.
Is that OK?
Well, we might want to split default_reloptions into two versions,
one for heaps and the other for indexes. But it doesn't bother me a
whole lot if we don't.
regards, tom lane
Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
Before we waste too much time thinking how this registering is to be
done, does anybody think that the current approach is OK and thus I
should just add the autovacuum options directly into StdRdOptions and
default_reloptions?
Given Simon's suggestion that i/o parameters should be per-tablespace I think
we might need to refactor this further.
I wonder if we could piggy-back on guc parameters. So you would register a guc
variable with a flag saying it's sensible to be set per-tablespace or
per-table.
--
Gregory Stark
EnterpriseDB http://www.enterprisedb.com
Ask me about EnterpriseDB's PostGIS support!
Gregory Stark <stark@enterprisedb.com> writes:
I wonder if we could piggy-back on guc parameters.
God, no. GUC is hopelessly complex already, we should *not* try to make
it track different values of a parameter for different tables.
Attaching a reloptions-like column to pg_tablespace might not be
unreasonable ... but I think that has little to do with Alvaro's
immediate problem.
regards, tom lane
Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
So I gave up waiting for someone else to do the reloptions patch for
autovacuum and started work on it myself.
Is it needed to keep backward compatibility?
I'd like to suggest to keep pg_catalog.pg_autovacuum as a system view
even after the options is put into reloptons, and the view to be
updatable using RULEs if possible.
Current pg_autovacuum-table approach has a benefit that
we can configure options by rule, for example:
INSERT INTO pg_autovacuu SELECT ... FROM pg_class WHERE ...;
But we will not able to do that if the settings will be in reloptions
because ALTER TABLE SET cannot be used with JOINs.
Regards,
---
ITAGAKI Takahiro
NTT Open Source Software Center
ITAGAKI Takahiro <itagaki.takahiro@oss.ntt.co.jp> writes:
Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:
So I gave up waiting for someone else to do the reloptions patch for
autovacuum and started work on it myself.
Is it needed to keep backward compatibility?
I'd like to suggest to keep pg_catalog.pg_autovacuum as a system view
even after the options is put into reloptons, and the view to be
updatable using RULEs if possible.
Ugh. No. It has been explicitly stated all along that pg_autovacuum
was a temporary API and that anyone depending on it could expect future
trouble.
But we will not able to do that if the settings will be in reloptions
because ALTER TABLE SET cannot be used with JOINs.
Any mechanism that a rule might use to set reloptions would be just
as usable in a join as the rule itself ...
regards, tom lane
Tom Lane wrote:
Gregory Stark <stark@enterprisedb.com> writes:
I wonder if we could piggy-back on guc parameters.
God, no. GUC is hopelessly complex already, we should *not* try to make
it track different values of a parameter for different tables.
Are there any more specific reasons than "it's very complex"? After
all, all the autovacuum options already exist as GUC parameters, so you
don't have to repeat all the validation code, for example.
Peter Eisentraut <peter_e@gmx.net> writes:
Tom Lane wrote:
God, no. GUC is hopelessly complex already, we should *not* try to make
it track different values of a parameter for different tables.
Are there any more specific reasons than "it's very complex"?
That one seems quite sufficient to me; but consider dump/restore if you
need more.
regards, tom lane
Alvaro Herrera escreveu:
So I gave up waiting for someone else to do the reloptions patch for
autovacuum and started work on it myself. What I soon discovered is
that on first blush it seems a lot easier than I had expected.
Sorry about that. :( I was swamped with PGCon Brasil and then I took
some days to rest. I'm expecting to finish it before next CF.
What did I already do? I refactored reloptions.c to support multiple
options. I tried to follow up the same way GUC do (of course, it is much
simpler). I'm thinking about removing (replacing?) StdRdOptions 'cause
we need a different struct to store reloptions. Suggestions?
I'm attaching the WIP patch so you can comment on it. I want to continue
working on it but I'm afraid you already did more than I do (in this
case, let me know for not duplicating efforts).
--
Euler Taveira de Oliveira
http://www.timbira.com/
Attachments:
relopt5.difftext/plain; name=relopt5.diffDownload
Index: src/backend/access/common/reloptions.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/common/reloptions.c,v
retrieving revision 1.11
diff -c -r1.11 reloptions.c
*** src/backend/access/common/reloptions.c 23 Jul 2008 17:29:53 -0000 1.11
--- src/backend/access/common/reloptions.c 10 Oct 2008 13:55:15 -0000
***************
*** 24,29 ****
--- 24,182 ----
#include "utils/guc.h"
#include "utils/rel.h"
+ /*
+ * Contents of pg_class.reloptions
+ *
+ * To add an option:
+ *
+ * (i) decide on a class (integer, double, bool), name, default value, upper
+ * and lower bounds (if applicable).
+ *
+ * (ii) add a record below.
+ *
+ * (iii) don't forget to document the option
+ */
+
+ static struct relopt_bool relOptBools[] =
+ {
+ {
+ {
+ "autovacuum_enabled",
+ "Enables autovacuum in this relation",
+ RO_BOOL
+ },
+ false
+ },
+ /* End-of-list marker */
+ {
+ {
+ NULL,
+ NULL,
+ RO_BOOL
+ },
+ false
+ }
+ };
+
+ static struct relopt_int relOptInts[] =
+ {
+ {
+ {
+ "fillfactor",
+ "Packs table pages only to this percentage",
+ RO_INT
+ },
+ 100,
+ 10,
+ 100
+ },
+ {
+ {
+ "autovacuum_vac_base_thresh",
+ "Minimum number of tuple updates or deletes prior to vacuum",
+ RO_INT
+ },
+ 50,
+ 0,
+ INT_MAX
+ },
+ {
+ {
+ "autovacuum_anl_base_thresh",
+ "Minimum number of tuple inserts, updates or deletes prior to analyze",
+ RO_INT
+ },
+ 50,
+ 0,
+ INT_MAX
+ },
+ {
+ {
+ "autovacuum_vac_cost_delay",
+ "Vacuum cost delay in milliseconds, for autovacuum",
+ RO_INT
+ },
+ 20,
+ -1,
+ 1000
+ },
+ {
+ {
+ "autovacuum_vac_cost_limit",
+ "Vacuum cost ammount available before napping, for autovacuum",
+ RO_INT
+ },
+ -1,
+ -1,
+ 10000
+ },
+ {
+ {
+ "autovacuum_freeze_min_age",
+ "Minimum age at which VACUUM should freeze a table row, for autovacuum",
+ RO_INT
+ },
+ 100000000,
+ 0,
+ 1000000000
+ },
+ {
+ {
+ "autovacuum_freeze_max_age",
+ "Age at which to autovacuum a table to prevent transaction ID wraparound",
+ RO_INT
+ },
+ 200000000,
+ 100000000,
+ 2000000000
+ },
+ /* End-of-list marker */
+ {
+ {
+ NULL,
+ NULL,
+ RO_INT
+ },
+ 0,
+ 0,
+ 0
+ }
+ };
+
+ struct relopt_real relOptReals[] =
+ {
+ {
+ {
+ "autovacuum_vac_scale_factor",
+ "Number of tuples inserts, updates or deletes prior to vacuum as a fraction of reltuples",
+ RO_REAL
+ },
+ 0.2,
+ 0.0,
+ 100.0
+ },
+ {
+ {
+ "autovacuum_anl_scale_factor",
+ "Number of tuples inserts, updates or deletes prior to analyze as a fraction of reltuples",
+ RO_REAL
+ },
+ 0.1,
+ 0.0,
+ 100.0
+ },
+ /* End-of-list marker */
+ {
+ {
+ NULL,
+ NULL,
+ RO_REAL
+ },
+ 0.0,
+ 0.0,
+ 0.0
+ }
+ };
/*
* Transform a relation options list (list of DefElem) into the text array
***************
*** 51,56 ****
--- 204,212 ----
ArrayBuildState *astate;
ListCell *cell;
+ ereport(DEBUG2,
+ (errmsg("starting transformRelOptions() ...")));
+
/* no change if empty list */
if (defList == NIL)
return oldOptions;
***************
*** 77,82 ****
--- 233,243 ----
char *text_str = VARDATA(oldoption);
int text_len = VARSIZE(oldoption) - VARHDRSZ;
+ char *tmp = text_str;
+ tmp[text_len] = '\0';
+ ereport(DEBUG1,
+ (errmsg("old reloption: %s", text_str)));
+
/* Search for a match in defList */
foreach(cell, defList)
{
***************
*** 93,98 ****
--- 254,261 ----
astate = accumArrayResult(astate, oldoptions[i],
false, TEXTOID,
CurrentMemoryContext);
+ ereport(DEBUG1,
+ (errmsg("added old reloption: %s", tmp)));
}
}
}
***************
*** 136,141 ****
--- 299,307 ----
SET_VARSIZE(t, len);
sprintf(VARDATA(t), "%s=%s", def->defname, value);
+ ereport(DEBUG1,
+ (errmsg("added new reloption: %s=%s", def->defname, value)));
+
astate = accumArrayResult(astate, PointerGetDatum(t),
false, TEXTOID,
CurrentMemoryContext);
***************
*** 147,152 ****
--- 313,321 ----
else
result = (Datum) 0;
+ ereport(DEBUG2,
+ (errmsg("ending transformRelOptions() ...")));
+
return result;
}
***************
*** 164,169 ****
--- 333,341 ----
int noptions;
int i;
+ ereport(DEBUG2,
+ (errmsg("starting untransformRelOptions() ...")));
+
/* Nothing to do if no options */
if (!PointerIsValid(DatumGetPointer(options)))
return result;
***************
*** 188,196 ****
--- 360,375 ----
*p++ = '\0';
val = (Node *) makeString(pstrdup(p));
}
+
+ ereport(DEBUG1,
+ (errmsg("added reloption: %s=%s", s, p)));
+
result = lappend(result, makeDefElem(pstrdup(s), val));
}
+ ereport(DEBUG2,
+ (errmsg("ending untransformRelOptions() ...")));
+
return result;
}
***************
*** 199,206 ****
* Interpret reloptions that are given in text-array format.
*
* options: array of "keyword=value" strings, as built by transformRelOptions
- * numkeywords: number of legal keywords
- * keywords: the allowed keywords
* values: output area
* validate: if true, throw error for unrecognized keywords.
*
--- 378,383 ----
***************
*** 209,221 ****
* containing the corresponding value, or NULL if the keyword does not appear.
*/
void
! parseRelOptions(Datum options, int numkeywords, const char *const * keywords,
! char **values, bool validate)
{
ArrayType *array;
Datum *optiondatums;
int noptions;
int i;
/* Initialize to "all defaulted" */
MemSet(values, 0, numkeywords * sizeof(char *));
--- 386,410 ----
* containing the corresponding value, or NULL if the keyword does not appear.
*/
void
! parseRelOptions(Datum options, char **values, bool validate, int minFillfactor)
{
ArrayType *array;
Datum *optiondatums;
int noptions;
int i;
+ int numkeywords = 0;
+
+ ereport(DEBUG2,
+ (errmsg("starting parseRelOptions() ...")));
+
+ for (i = 0; relOptBools[i].gen.name; i++)
+ numkeywords++;
+ for (i = 0; relOptInts[i].gen.name; i++)
+ numkeywords++;
+ for (i = 0; relOptReals[i].gen.name; i++)
+ numkeywords++;
+ ereport(DEBUG1,
+ (errmsg("number of keywords: %d", numkeywords)));
/* Initialize to "all defaulted" */
MemSet(values, 0, numkeywords * sizeof(char *));
***************
*** 236,267 ****
text *optiontext = DatumGetTextP(optiondatums[i]);
char *text_str = VARDATA(optiontext);
int text_len = VARSIZE(optiontext) - VARHDRSZ;
! int j;
/* Search for a match in keywords */
! for (j = 0; j < numkeywords; j++)
{
! int kw_len = strlen(keywords[j]);
if (text_len > kw_len && text_str[kw_len] == '=' &&
! pg_strncasecmp(text_str, keywords[j], kw_len) == 0)
{
! char *value;
! int value_len;
if (values[j] && validate)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! errmsg("parameter \"%s\" specified more than once",
! keywords[j])));
value_len = text_len - kw_len - 1;
value = (char *) palloc(value_len + 1);
memcpy(value, text_str + kw_len + 1, value_len);
value[value_len] = '\0';
values[j] = value;
break;
}
}
if (j >= numkeywords && validate)
{
char *s;
--- 425,574 ----
text *optiontext = DatumGetTextP(optiondatums[i]);
char *text_str = VARDATA(optiontext);
int text_len = VARSIZE(optiontext) - VARHDRSZ;
! int j = 0;
! bool found = false;
!
! char *tmp = text_str;
! tmp[text_len] = '\0';
! ereport(DEBUG1,
! (errmsg("parsing reloption %s ...", tmp)));
/* Search for a match in keywords */
! while (relOptBools[j].gen.name)
{
! int kw_len = strlen(relOptBools[j].gen.name);
if (text_len > kw_len && text_str[kw_len] == '=' &&
! pg_strcasecmp(text_str, relOptBools[j].gen.name, kw_len) == 0)
{
! char *value;
! int value_len;
if (values[j] && validate)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
! errmsg("parameter \"%s\" specified more than once",
! relOptBools[j].gen.name)));
!
value_len = text_len - kw_len - 1;
value = (char *) palloc(value_len + 1);
memcpy(value, text_str + kw_len + 1, value_len);
value[value_len] = '\0';
+
+ if (parse_bool(value, NULL) == false && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid input value for parameter %s: \"%s\"",
+ relOptBools[j].gen.name, value),
+ errhint("value must be a boolean")));
+
values[j] = value;
+
+ found = true;
break;
}
+
+ j++;
}
+
+ while (relOptInts[j].gen.name || !found)
+ {
+ int kw_len = strlen(relOptInts[j].gen.name);
+
+ if (text_len > kw_len && text_str[kw_len] == '=' &&
+ pg_strcasecmp(text_str, relOptInts[j].gen.name, kw_len) == 0)
+ {
+ char *value;
+ int value_len;
+
+ if (values[j] && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter \"%s\" specified more than once",
+ relOptInts[j].gen.name)));
+
+ value_len = text_len - kw_len - 1;
+ value = (char *) palloc(value_len + 1);
+ memcpy(value, text_str + kw_len + 1, value_len);
+ value[value_len] = '\0';
+
+ if (parse_int(value, NULL, 0, NULL) == false && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid input value for parameter %s: \"%s\"",
+ relOptBools[j].gen.name, value),
+ errhint("value must be an integer")));
+
+ if ((value < relOptInts[j].min || value > relOptInts[j].max) && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("%s=%s is out of range (should be between %d and %d)",
+ relOptInts[j].gen.name, value, relOptInts[j].min, relOptInts[j].max)));
+
+ /*
+ * Especial check for fillfactor because minimum fillfactor values
+ * are AMs and/or heap dependant. We don't need to check upper
+ * limit because we already did it above.
+ */
+ if (pg_strcasecmp(relOptInts[j].gen.name, "fillfactor") == 0 &&
+ value < minFillfactor && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("fillfactor=%s is out of range (should be between %d and 100)",
+ value, minFillfactor)));
+
+ values[j] = value;
+
+ found = true;
+ break;
+ }
+
+ j++;
+ }
+
+ while (relOptReals[j].gen.name || !found)
+ {
+ int kw_len = strlen(relOptReals[j].gen.name);
+
+ if (text_len > kw_len && text_str[kw_len] == '=' &&
+ pg_strcasecmp(text_str, relOptReals[j].gen.name, kw_len) == 0)
+ {
+ char *value;
+ int value_len;
+
+ if (values[j] && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter \"%s\" specified more than once",
+ relOptReals[j].gen.name)));
+
+ value_len = text_len - kw_len - 1;
+ value = (char *) palloc(value_len + 1);
+ memcpy(value, text_str + kw_len + 1, value_len);
+ value[value_len] = '\0';
+
+ if (parse_real(value, NULL) == false && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid input value for parameter %s: \"%s\"",
+ relOptBools[j].gen.name, value),
+ errhint("value must be a float")));
+
+ if ((value < relOptReals[j].min || value > relOptReals[j].max) && validate)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("%s=%s is out of range (should be between %d and %d)",
+ relOptReals[j].gen.name, value, relOptReals[j].min, relOptReals[j].max)));
+
+ values[j] = value;
+
+ found = true;
+ break;
+ }
+
+ j++;
+ }
+
if (j >= numkeywords && validate)
{
char *s;
***************
*** 276,281 ****
--- 583,591 ----
errmsg("unrecognized parameter \"%s\"", s)));
}
}
+
+ ereport(DEBUG2,
+ (errmsg("ending parseRelOptions() ...")));
}
***************
*** 286,297 ****
default_reloptions(Datum reloptions, bool validate,
int minFillfactor, int defaultFillfactor)
{
- static const char *const default_keywords[1] = {"fillfactor"};
char *values[1];
int fillfactor;
StdRdOptions *result;
! parseRelOptions(reloptions, 1, default_keywords, values, validate);
/*
* If no options, we can just return NULL rather than doing anything.
--- 596,609 ----
default_reloptions(Datum reloptions, bool validate,
int minFillfactor, int defaultFillfactor)
{
char *values[1];
int fillfactor;
StdRdOptions *result;
! ereport(DEBUG2,
! (errmsg("starting default_options() ...")));
!
! parseRelOptions(reloptions, values, validate, minFillfactor);
/*
* If no options, we can just return NULL rather than doing anything.
***************
*** 301,331 ****
if (values[0] == NULL)
return NULL;
- if (!parse_int(values[0], &fillfactor, 0, NULL))
- {
- if (validate)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("fillfactor must be an integer: \"%s\"",
- values[0])));
- return NULL;
- }
-
- if (fillfactor < minFillfactor || fillfactor > 100)
- {
- if (validate)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("fillfactor=%d is out of range (should be between %d and 100)",
- fillfactor, minFillfactor)));
- return NULL;
- }
-
result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
SET_VARSIZE(result, sizeof(StdRdOptions));
result->fillfactor = fillfactor;
return (bytea *) result;
}
--- 613,626 ----
if (values[0] == NULL)
return NULL;
result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
SET_VARSIZE(result, sizeof(StdRdOptions));
result->fillfactor = fillfactor;
+ ereport(DEBUG2,
+ (errmsg("ending default_reloptions() ...")));
+
return (bytea *) result;
}
***************
*** 336,344 ****
bytea *
heap_reloptions(char relkind, Datum reloptions, bool validate)
{
! return default_reloptions(reloptions, validate,
! HEAP_MIN_FILLFACTOR,
! HEAP_DEFAULT_FILLFACTOR);
}
--- 631,642 ----
bytea *
heap_reloptions(char relkind, Datum reloptions, bool validate)
{
! ereport(DEBUG2,
! (errmsg("starting heap_reloptions() ...")));
!
! return default_reloptions(reloptions, validate,
! HEAP_MIN_FILLFACTOR,
! HEAP_DEFAULT_FILLFACTOR);
}
***************
*** 356,361 ****
--- 654,662 ----
FunctionCallInfoData fcinfo;
Datum result;
+ ereport(DEBUG2,
+ (errmsg("starting index_reloptions() ...")));
+
Assert(RegProcedureIsValid(amoptions));
/* Assume function is strict */
***************
*** 377,381 ****
--- 678,685 ----
if (fcinfo.isnull || DatumGetPointer(result) == NULL)
return NULL;
+ ereport(DEBUG2,
+ (errmsg("ending index_reloptions() ...")));
+
return DatumGetByteaP(result);
}
Index: src/backend/access/gin/ginutil.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/gin/ginutil.c,v
retrieving revision 1.17
diff -c -r1.17 ginutil.c
*** src/backend/access/gin/ginutil.c 30 Sep 2008 10:52:10 -0000 1.17
--- src/backend/access/gin/ginutil.c 2 Oct 2008 20:33:13 -0000
***************
*** 339,347 ****
#define GIN_MIN_FILLFACTOR 10
#define GIN_DEFAULT_FILLFACTOR 100
! result = default_reloptions(reloptions, validate,
! GIN_MIN_FILLFACTOR,
GIN_DEFAULT_FILLFACTOR);
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
--- 339,350 ----
#define GIN_MIN_FILLFACTOR 10
#define GIN_DEFAULT_FILLFACTOR 100
! /* TODO how can we pass the min|default fillfactor to reloptions? */
! /* XXX different AM has different values! */
! result = default_reloptions(reloptions, validate,
! GIN_MIN_FILLFACTOR,
GIN_DEFAULT_FILLFACTOR);
+
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
Index: src/backend/access/gist/gistutil.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/gist/gistutil.c,v
retrieving revision 1.31
diff -c -r1.31 gistutil.c
*** src/backend/access/gist/gistutil.c 30 Sep 2008 10:52:10 -0000 1.31
--- src/backend/access/gist/gistutil.c 2 Oct 2008 20:33:28 -0000
***************
*** 670,678 ****
bool validate = PG_GETARG_BOOL(1);
bytea *result;
! result = default_reloptions(reloptions, validate,
! GIST_MIN_FILLFACTOR,
GIST_DEFAULT_FILLFACTOR);
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
--- 670,681 ----
bool validate = PG_GETARG_BOOL(1);
bytea *result;
! /* TODO how can we pass the min|default fillfactor to reloptions? */
! /* XXX different AM has different values! */
! result = default_reloptions(reloptions, validate,
! GIST_MIN_FILLFACTOR,
GIST_DEFAULT_FILLFACTOR);
+
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
Index: src/backend/access/hash/hashutil.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/hash/hashutil.c,v
retrieving revision 1.57
diff -c -r1.57 hashutil.c
*** src/backend/access/hash/hashutil.c 15 Sep 2008 18:43:41 -0000 1.57
--- src/backend/access/hash/hashutil.c 2 Oct 2008 20:32:48 -0000
***************
*** 224,232 ****
bool validate = PG_GETARG_BOOL(1);
bytea *result;
! result = default_reloptions(reloptions, validate,
! HASH_MIN_FILLFACTOR,
HASH_DEFAULT_FILLFACTOR);
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
--- 224,235 ----
bool validate = PG_GETARG_BOOL(1);
bytea *result;
! /* TODO how can we pass the min|default fillfactor to reloptions? */
! /* XXX different AM has different values! */
! result = default_reloptions(reloptions, validate,
! HASH_MIN_FILLFACTOR,
HASH_DEFAULT_FILLFACTOR);
+
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
Index: src/backend/access/nbtree/nbtutils.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/nbtree/nbtutils.c,v
retrieving revision 1.91
diff -c -r1.91 nbtutils.c
*** src/backend/access/nbtree/nbtutils.c 19 Jun 2008 00:46:03 -0000 1.91
--- src/backend/access/nbtree/nbtutils.c 2 Oct 2008 20:32:35 -0000
***************
*** 1402,1410 ****
bool validate = PG_GETARG_BOOL(1);
bytea *result;
! result = default_reloptions(reloptions, validate,
! BTREE_MIN_FILLFACTOR,
BTREE_DEFAULT_FILLFACTOR);
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
--- 1402,1413 ----
bool validate = PG_GETARG_BOOL(1);
bytea *result;
! /* TODO how can we pass the min|default fillfactor to reloptions? */
! /* XXX different AM has different values! */
! result = default_reloptions(reloptions, validate,
! BTREE_MIN_FILLFACTOR,
BTREE_DEFAULT_FILLFACTOR);
+
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
Index: src/include/access/reloptions.h
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/include/access/reloptions.h,v
retrieving revision 1.5
diff -c -r1.5 reloptions.h
*** src/include/access/reloptions.h 1 Jan 2008 19:45:56 -0000 1.5
--- src/include/access/reloptions.h 7 Oct 2008 04:57:59 -0000
***************
*** 20,36 ****
#include "nodes/pg_list.h"
extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool ignoreOids, bool isReset);
extern List *untransformRelOptions(Datum options);
! extern void parseRelOptions(Datum options, int numkeywords,
! const char *const * keywords,
! char **values, bool validate);
! extern bytea *default_reloptions(Datum reloptions, bool validate,
! int minFillfactor, int defaultFillfactor);
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
--- 20,85 ----
#include "nodes/pg_list.h"
+ /* types supported by reloptions */
+ enum ro_type
+ {
+ RO_BOOL,
+ RO_INT,
+ RO_REAL
+ };
+
+ /* kind supported by reloptions */
+ enum ro_kind
+ {
+ RO_INDEX,
+ RO_HEAP
+ };
+
+ /* generic struct to hold shared data */
+ struct relopt_gen
+ {
+ const char *name;
+ const char *desc;
+ enum ro_type type; /* type of variable */
+ enum ro_kind kind; /* index or heap? */
+ };
+
+ /* reloptions records for specific variable types */
+ struct relopt_bool
+ {
+ struct relopt_gen gen;
+ bool value;
+ bool reset_value; /* XXX useful? */
+ };
+
+ struct relopt_int
+ {
+ struct relopt_gen gen;
+ int value;
+ int min;
+ int max;
+ int reset_value; /* XXX useful? */
+ };
+
+ struct relopt_real
+ {
+ struct relopt_gen gen;
+ double value;
+ double min;
+ double max;
+ double reset_value; /* XXX useful? */
+ };
+
extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool ignoreOids, bool isReset);
extern List *untransformRelOptions(Datum options);
! extern void parseRelOptions(Datum options, char **values, bool validate,
! int minFillfactor);
! extern bytea *default_reloptions(Datum reloptions, bool validate,
! int minFillfactor, int defaultFillfactor);
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
Euler Taveira de Oliveira wrote:
What did I already do? I refactored reloptions.c to support multiple
options. I tried to follow up the same way GUC do (of course, it is much
simpler). I'm thinking about removing (replacing?) StdRdOptions 'cause
we need a different struct to store reloptions. Suggestions?I'm attaching the WIP patch so you can comment on it. I want to continue
working on it but I'm afraid you already did more than I do (in this
case, let me know for not duplicating efforts).
Interesting. The main problem with this patch is that it loses the
ability to pass to parseRelOptions the set of options that are valid for
each context. Right now all callers use the same list comprising only
fillfactor, but my guess is that once we add new options it will make
sense to start differentiating. It makes no sense for indexes to have
autovacuum options, for example.
This is why I suggested in the email that started this thread we needed
some sort of registering capability (which was thrown down). I think
the main idea in your patch is fine, and better than what I was doing
which was just adding every option in default_reloptions. However it
needs to be adjusted somehow so that it doesn't mix all the options.
Maybe we could add a "category" bitmask for which each option would be
valid.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Alvaro Herrera escreveu:
Maybe we could add a "category" bitmask for which each option would be
valid.
The category tests are fine, that's why I introduced relopt_gen.kind but
I'm not using it yet. I'll try to refactor it to use bitmask (some
options could be used to both -- fillfactor) and to add it in the
validation code.
--
Euler Taveira de Oliveira
http://www.timbira.com/
Euler Taveira de Oliveira wrote:
Alvaro Herrera escreveu:
Maybe we could add a "category" bitmask for which each option would be
valid.The category tests are fine, that's why I introduced relopt_gen.kind but
I'm not using it yet.
Ah, right, I hadn't noticed the kind stuff, maybe because it's unused
;-)
I'll try to refactor it to use bitmask (some options could be used to
both -- fillfactor) and to add it in the validation code.
Right, that's why I suggested using a bitmask.
Okay, so I'll let you deal with this for a while yet. A minor
suggestion: label the enum members distinctively, i.e. instead of
RO_BOOL perhaps use RELOPT_TYPE_BOOL, and RO_HEAP should be
RELOPT_KIND_HEAP (note this cannot be a plain enum, each category needs
a separate bit).
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Alvaro Herrera <alvherre@commandprompt.com> writes:
Okay, so I'll let you deal with this for a while yet. A minor
suggestion: label the enum members distinctively, i.e. instead of
RO_BOOL perhaps use RELOPT_TYPE_BOOL, and RO_HEAP should be
RELOPT_KIND_HEAP (note this cannot be a plain enum, each category needs
a separate bit).
My first reaction was that the categories should just be the different
possible values of relkind. However, it also seems possible that there
could be index-AM-specific reloptions. So maybe what we need is a
categorization that is like relkind but breaks down RELKIND_INDEX into a
category per AM.
regards, tom lane
Euler Taveira de Oliveira wrote:
Alvaro Herrera escreveu:
So I gave up waiting for someone else to do the reloptions patch for
autovacuum and started work on it myself. What I soon discovered is
that on first blush it seems a lot easier than I had expected.Sorry about that. :( I was swamped with PGCon Brasil and then I took
some days to rest. I'm expecting to finish it before next CF.
So did this go anywhere?
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
I have a comment about reloptions of autovacuum parameters:
I'd like to have an easier way to extract individual parameters.
Alvaro Herrera <alvherre@commandprompt.com> wrote:
Euler Taveira de Oliveira wrote:
What did I already do? I refactored reloptions.c to support multiple
options. I tried to follow up the same way GUC do (of course, it is much
simpler). I'm thinking about removing (replacing?) StdRdOptions 'cause
we need a different struct to store reloptions. Suggestions?Interesting.
We store reloptions as an array of 'key=value' text, but there is
no official way to read each parameter. I always create an user
defined function to extract fillfactors, but it would be better
if we have a standard method to do that.
---- [brute force way]
CREATE FUNCTION pg_fillfactor(reloptions text[], relam OID)
RETURNS integer AS
$$
SELECT (regexp_matches(array_to_string($1, '/'),
'fillfactor=([0-9]+)'))[1]::integer AS fillfactor
UNION ALL
SELECT CASE $2
WHEN 0 THEN 100 -- heap
WHEN 403 THEN 90 -- btree
WHEN 405 THEN 70 -- hash
WHEN 783 THEN 90 -- gist
WHEN 2742 THEN 100 -- gin
END
LIMIT 1;
$$
LANGUAGE sql STABLE;
----
Regards,
---
ITAGAKI Takahiro
NTT Open Source Software Center
ITAGAKI Takahiro escreveu:
[Sorry for the delay. I'm preparing the final patch and in a day or so
I'll post it.]
I have a comment about reloptions of autovacuum parameters:
I'd like to have an easier way to extract individual parameters.Alvaro Herrera <alvherre@commandprompt.com> wrote:
Euler Taveira de Oliveira wrote:
What did I already do? I refactored reloptions.c to support multiple
options. I tried to follow up the same way GUC do (of course, it is much
simpler). I'm thinking about removing (replacing?) StdRdOptions 'cause
we need a different struct to store reloptions. Suggestions?Interesting.
We store reloptions as an array of 'key=value' text, but there is
no official way to read each parameter. I always create an user
defined function to extract fillfactors, but it would be better
if we have a standard method to do that.
We will have an official function (getRelOptions()?) to extract the
reloption (autovacuum) parameters because we need to transform
pg_autovacuum catalog table in a view to maintain backward compatibility.
--
Euler Taveira de Oliveira
http://www.timbira.com/
Euler Taveira de Oliveira wrote:
We will have an official function (getRelOptions()?) to extract the
reloption (autovacuum) parameters because we need to transform
pg_autovacuum catalog table in a view to maintain backward compatibility.
Why? I'd say don't waste your time. If anything, it can be done after
the initial patch has been committed.
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Euler Taveira de Oliveira <euler@timbira.com> wrote:
We will have an official function (getRelOptions()?) to extract the
reloption (autovacuum) parameters
Yeah, I want it, but...
because we need to transform
pg_autovacuum catalog table in a view to maintain backward compatibility.
I don't think we need pg_autovacuum in 8.4 because it is a deprecated API.
However, we should provide some easier methods to create an user-defined
pg_autovacuum view in case that users really need it.
Regards,
---
ITAGAKI Takahiro
NTT Open Source Software Center
Euler Taveira de Oliveira escreveu:
[Sorry for the delay. I'm preparing the final patch and in a day or so
I'll post it.]
Here is the patch that replace pg_autovaccum catalog with reloptions. I
refactored the reloptions.c to support multiple parameters and made the
action of adding a new option an easy task. I'm testing it yet, so don't
expect it to work properly. I'll prepare docs as soon as I finish the
tests. Do i have to prepare some regression tests?
I don't provide a pg_autovacuum view as suggested by Itagari-san [1]http://archives.postgresql.org/pgsql-hackers/2008-11/msg00830.php but
if others agree that we need it, I will work on it. I don't if we need a
function (wrapper around getRelOption()) to get an option from
reloptions array.
I add an ugly-hack to \d+ foo. IMHO, it'll be good to know what options
are used by table/index foo (we already do it for oids) but I'm not
happy with my suggestion.
I move RelationGet*() functions from rel.h. That's because we need some
knowledge that's only in reloptions.c (getRelOptions). But I want to
avoid including reloptions.h at some files.
Comments?
PS> don't forget to remove include/catalog/pg_autovacuum.h
[1]: http://archives.postgresql.org/pgsql-hackers/2008-11/msg00830.php
--
Euler Taveira de Oliveira
http://www.timbira.com/
Attachments:
Here is the patch that replace pg_autovaccum catalog with reloptions. I
refactored the reloptions.c to support multiple parameters and made the
action of adding a new option an easy task. I'm testing it yet, so don't
expect it to work properly. I'll prepare docs as soon as I finish the
tests. Do i have to prepare some regression tests?I don't provide a pg_autovacuum view as suggested by Itagari-san [1] but
if others agree that we need it, I will work on it. I don't if we need a
function (wrapper around getRelOption()) to get an option from
reloptions array.I add an ugly-hack to \d+ foo. IMHO, it'll be good to know what options
are used by table/index foo (we already do it for oids) but I'm not
happy with my suggestion.I move RelationGet*() functions from rel.h. That's because we need some
knowledge that's only in reloptions.c (getRelOptions). But I want to
avoid including reloptions.h at some files.Comments?
PS> don't forget to remove include/catalog/pg_autovacuum.h
Several things related to this patch have been committed:
http://archives.postgresql.org/message-id/20081219143958.6F2DD7563FE@cvs.postgresql.org
http://archives.postgresql.org/message-id/20090105171428.77B29754A17@cvs.postgresql.org
(and several follow-on commits)
What still remains to be done for 8.4?
...Robert
Robert Haas escreveu:
Several things related to this patch have been committed:
http://archives.postgresql.org/message-id/20081219143958.6F2DD7563FE@cvs.postgresql.org
http://archives.postgresql.org/message-id/20090105171428.77B29754A17@cvs.postgresql.org
(and several follow-on commits)What still remains to be done for 8.4?
autovacuum part?
--
Euler Taveira de Oliveira
http://www.timbira.com/
On Sun, Jan 11, 2009 at 6:47 PM, Euler Taveira de Oliveira
<euler@timbira.com> wrote:
Robert Haas escreveu:
Several things related to this patch have been committed:
http://archives.postgresql.org/message-id/20081219143958.6F2DD7563FE@cvs.postgresql.org
http://archives.postgresql.org/message-id/20090105171428.77B29754A17@cvs.postgresql.org
(and several follow-on commits)What still remains to be done for 8.4?
autovacuum part?
I guess Alvaro is working on that? Or are you?
...Robert
Robert Haas escribi�:
On Sun, Jan 11, 2009 at 6:47 PM, Euler Taveira de Oliveira
<euler@timbira.com> wrote:Robert Haas escreveu:
Several things related to this patch have been committed:
http://archives.postgresql.org/message-id/20081219143958.6F2DD7563FE@cvs.postgresql.org
http://archives.postgresql.org/message-id/20090105171428.77B29754A17@cvs.postgresql.org
(and several follow-on commits)What still remains to be done for 8.4?
autovacuum part?
I guess Alvaro is working on that? Or are you?
I have a followup patch that allows one to use a namespace in ALTER
TABLE SET commands, like this:
alter table foo set (toast.fillfactor = 50)
This is still WIP because it has some minor annoyances. I will finish
and commit the table-based amoptions infrastructure and then be back on
the namespace patch.
This namespace patch is a prerequisite of the autovacuum work, because
without it, it is impossible to change autovacuum settings for toast
tables, which would be a regression.
I have a separate branch on which I keep the old patch from Euler
updated to the current reloptions code; so it is probably very similar
to what Euler just sent. (I'll have a look at that soon anyway.)
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Alvaro Herrera escribi�:
I have a separate branch on which I keep the old patch from Euler
updated to the current reloptions code; so it is probably very similar
to what Euler just sent. (I'll have a look at that soon anyway.)
Huh, nevermind -- I thought that Euler had just sent an updated version
of his patch, but only now I noticed that the message I was looking at
is dated Nov. 21st.
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Alvaro Herrera escreveu:
Alvaro Herrera escribi�:
I have a separate branch on which I keep the old patch from Euler
updated to the current reloptions code; so it is probably very similar
to what Euler just sent. (I'll have a look at that soon anyway.)Huh, nevermind -- I thought that Euler had just sent an updated version
of his patch, but only now I noticed that the message I was looking at
is dated Nov. 21st.
And I did it (It is even listed in the wiki). Last version was [1]http://archives.postgresql.org/pgsql-hackers/2008-12/msg00292.php. I fixed
some problems and added some docs.
[1]: http://archives.postgresql.org/pgsql-hackers/2008-12/msg00292.php
--
Euler Taveira de Oliveira
http://www.timbira.com/
Euler Taveira de Oliveira escribi�:
Alvaro Herrera escreveu:
Alvaro Herrera escribi�:
I have a separate branch on which I keep the old patch from Euler
updated to the current reloptions code; so it is probably very similar
to what Euler just sent. (I'll have a look at that soon anyway.)Huh, nevermind -- I thought that Euler had just sent an updated version
of his patch, but only now I noticed that the message I was looking at
is dated Nov. 21st.And I did it (It is even listed in the wiki). Last version was [1]. I fixed
some problems and added some docs.
Yes, the autovacuum patch I have is loosely based on that one IIRC. (I
modified it heavily though.)
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Alvaro Herrera wrote:
Euler Taveira de Oliveira escribi�:
Alvaro Herrera escreveu:
Alvaro Herrera escribi�:
I have a separate branch on which I keep the old patch from Euler
updated to the current reloptions code; so it is probably very similar
to what Euler just sent. (I'll have a look at that soon anyway.)Huh, nevermind -- I thought that Euler had just sent an updated version
of his patch, but only now I noticed that the message I was looking at
is dated Nov. 21st.And I did it (It is even listed in the wiki). Last version was [1]. I fixed
some problems and added some docs.Yes, the autovacuum patch I have is loosely based on that one IIRC. (I
modified it heavily though.)
Could someone udpate the status of this item in the commitfest wiki?
Alvaro Herrera escribi�:
Euler Taveira de Oliveira escribi�:
And I did it (It is even listed in the wiki). Last version was [1]. I fixed
some problems and added some docs.Yes, the autovacuum patch I have is loosely based on that one IIRC. (I
modified it heavily though.)
Here's my proposed patch. There is a bug in the handling of TOAST
tables; I'm sending this as a WIP to add it to the commitfest status
page for this patch.
This also needs to be merged with my other patch to handle reloptions
namespaces, which will allow us to set reloptions for TOAST tables.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Attachments:
reloptions-autovacuum-2.patchtext/x-diff; charset=us-asciiDownload
Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.191
diff -c -p -r2.191 catalogs.sgml
*** doc/src/sgml/catalogs.sgml 22 Jan 2009 20:15:59 -0000 2.191
--- doc/src/sgml/catalogs.sgml 23 Jan 2009 15:30:29 -0000
***************
*** 89,99 ****
</row>
<row>
- <entry><link linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</structname></link></entry>
- <entry>per-relation autovacuum configuration parameters</entry>
- </row>
-
- <row>
<entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
<entry>casts (data type conversions)</entry>
</row>
--- 89,94 ----
***************
*** 1256,1433 ****
</sect1>
- <sect1 id="catalog-pg-autovacuum">
- <title><structname>pg_autovacuum</structname></title>
-
- <indexterm zone="catalog-pg-autovacuum">
- <primary>pg_autovacuum</primary>
- </indexterm>
-
- <indexterm zone="catalog-pg-autovacuum">
- <primary>autovacuum</primary>
- <secondary>table-specific configuration</secondary>
- </indexterm>
-
- <para>
- The catalog <structname>pg_autovacuum</structname> stores optional
- per-relation configuration parameters for the autovacuum daemon.
- If there is an entry here for a particular relation, the given
- parameters will be used for autovacuuming that table. If no entry
- is present, the system-wide defaults will be used. For more information
- about the autovacuum daemon, see <xref linkend="autovacuum">.
- </para>
-
- <note>
- <para>
- It is likely that <structname>pg_autovacuum</structname> will disappear
- in a future release, with the information instead being kept in
- <structname>pg_class</>.<structfield>reloptions</> entries.
- </para>
- </note>
-
- <table>
- <title><structname>pg_autovacuum</> Columns</title>
-
- <tgroup cols=4>
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Type</entry>
- <entry>References</entry>
- <entry>Description</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry><structfield>vacrelid</structfield></entry>
- <entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
- <entry>The table this entry is for</entry>
- </row>
-
- <row>
- <entry><structfield>enabled</structfield></entry>
- <entry><type>bool</type></entry>
- <entry></entry>
- <entry>If false, this table will not be autovacuumed, except
- to prevent transaction ID wraparound</entry>
- </row>
-
- <row>
- <entry><structfield>vac_base_thresh</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Minimum number of modified tuples before vacuum</entry>
- </row>
-
- <row>
- <entry><structfield>vac_scale_factor</structfield></entry>
- <entry><type>float4</type></entry>
- <entry></entry>
- <entry>Multiplier for <structfield>reltuples</> to add to
- <structfield>vac_base_thresh</></entry>
- </row>
-
- <row>
- <entry><structfield>anl_base_thresh</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Minimum number of modified tuples before analyze</entry>
- </row>
-
- <row>
- <entry><structfield>anl_scale_factor</structfield></entry>
- <entry><type>float4</type></entry>
- <entry></entry>
- <entry>Multiplier for <structfield>reltuples</> to add to
- <structfield>anl_base_thresh</></entry>
- </row>
-
- <row>
- <entry><structfield>vac_cost_delay</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_cost_delay</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>vac_cost_limit</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_cost_limit</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_min_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_freeze_min_age</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_max_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>autovacuum_freeze_max_age</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_table_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_freeze_table_age</> parameter</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- The autovacuum daemon will initiate a <command>VACUUM</> operation
- on a particular table when the number of updated or deleted tuples
- exceeds <structfield>vac_base_thresh</structfield> plus
- <structfield>vac_scale_factor</structfield> times the number of
- live tuples currently estimated to be in the relation.
- Similarly, it will initiate an <command>ANALYZE</> operation
- when the number of inserted, updated or deleted tuples
- exceeds <structfield>anl_base_thresh</structfield> plus
- <structfield>anl_scale_factor</structfield> times the number of
- live tuples currently estimated to be in the relation.
- </para>
-
- <para>
- Also, the autovacuum daemon will perform a <command>VACUUM</> operation
- to prevent transaction ID wraparound if the table's
- <structname>pg_class</>.<structfield>relfrozenxid</> field attains an age
- of more than <structfield>freeze_max_age</> transactions, whether the table
- has been changed or not, even if
- <structname>pg_autovacuum</>.<structfield>enabled</> is set to
- <literal>false</> for it. The system will launch autovacuum to perform
- such <command>VACUUM</>s even if autovacuum is otherwise disabled.
- See <xref linkend="vacuum-for-wraparound"> for more about wraparound
- prevention.
- </para>
-
- <para>
- Any of the numerical fields can contain <literal>-1</> (or indeed
- any negative value) to indicate that the system-wide default should
- be used for this particular value. Observe that the
- <structfield>vac_cost_delay</> variable inherits its default value from the
- <xref linkend="guc-autovacuum-vacuum-cost-delay"> configuration parameter,
- or from <xref linkend="guc-vacuum-cost-delay"> if the former is set to a
- negative value. The same applies to <structfield>vac_cost_limit</>.
- Also, autovacuum will ignore attempts to set a per-table
- <structfield>freeze_max_age</> larger than the system-wide setting (it can
- only be set smaller), and the <structfield>freeze_min_age</> value will be
- limited to half the system-wide <xref
- linkend="guc-autovacuum-freeze-max-age"> setting. Note that while you
- can set <structfield>freeze_max_age</> very small, or even zero, this
- is usually unwise since it will force frequent vacuuming.
- </para>
-
- </sect1>
-
-
<sect1 id="catalog-pg-cast">
<title><structname>pg_cast</structname></title>
--- 1251,1256 ----
Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.206
diff -c -p -r1.206 config.sgml
*** doc/src/sgml/config.sgml 16 Jan 2009 13:27:23 -0000 1.206
--- doc/src/sgml/config.sgml 16 Jan 2009 16:48:50 -0000
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3548,3554 ****
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3548,3554 ----
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_class</>.<structfield>reloptions</>.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3566,3572 ****
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3566,3572 ----
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_class</>.<structfield>reloptions</>.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3585,3591 ****
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3585,3591 ----
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_class</>.<structfield>reloptions</>.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3604,3610 ****
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3604,3610 ----
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_class</>.<structfield>reloptions</>.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3625,3631 ****
The default is 200 million transactions.
This parameter can only be set at server start, but the setting
can be reduced for individual tables by entries in
! <structname>pg_autovacuum</>.
For more information see <xref linkend="vacuum-for-wraparound">.
</para>
</listitem>
--- 3625,3631 ----
The default is 200 million transactions.
This parameter can only be set at server start, but the setting
can be reduced for individual tables by entries in
! <structname>pg_class</>.<structfield>reloptions</>.
For more information see <xref linkend="vacuum-for-wraparound">.
</para>
</listitem>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3646,3652 ****
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3646,3652 ----
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_class</>.<structfield>reloptions</>.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3668,3674 ****
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3668,3674 ----
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
This setting can be overridden for individual tables by entries in
! <structname>pg_class</>.<structfield>reloptions</>.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/maintenance.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/maintenance.sgml,v
retrieving revision 1.89
diff -c -p -r1.89 maintenance.sgml
*** doc/src/sgml/maintenance.sgml 16 Jan 2009 13:27:23 -0000 1.89
--- doc/src/sgml/maintenance.sgml 16 Jan 2009 17:04:19 -0000
*************** analyze threshold = analyze base thresho
*** 604,668 ****
<para>
The default thresholds and scale factors are taken from
<filename>postgresql.conf</filename>, but it is possible to override them
! on a table-by-table basis by making entries in the system catalog
<link
! linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</></link>.
! If a <structname>pg_autovacuum</structname> row exists for a particular
! table, the settings it specifies are applied; otherwise the global
! settings are used. See <xref linkend="runtime-config-autovacuum"> for
! more details on the global settings.
</para>
<para>
! Besides the base threshold values and scale factors, there are five
! more parameters that can be set for each table in
! <structname>pg_autovacuum</structname>.
! The first, <structname>pg_autovacuum</>.<structfield>enabled</>,
can be set to <literal>false</literal> to instruct the autovacuum daemon
to skip that particular table entirely. In this case
autovacuum will only touch the table if it must do so
to prevent transaction ID wraparound.
The next two parameters, the vacuum cost delay
! (<structname>pg_autovacuum</structname>.<structfield>vac_cost_delay</structfield>)
! and the vacuum cost limit
! (<structname>pg_autovacuum</structname>.<structfield>vac_cost_limit</structfield>),
! are used to set table-specific values for the
<xref linkend="runtime-config-resource-vacuum-cost" endterm="runtime-config-resource-vacuum-cost-title">
feature.
! The last two parameters,
! (<structname>pg_autovacuum</structname>.<structfield>freeze_min_age</structfield>)
! and
! (<structname>pg_autovacuum</structname>.<structfield>freeze_max_age</structfield>),
! are used to set table-specific values for
! <xref linkend="guc-vacuum-freeze-min-age"> and
! <xref linkend="guc-autovacuum-freeze-max-age"> respectively.
</para>
<para>
! If any of the values in <structname>pg_autovacuum</structname>
! are set to a negative number, or if a row is not present at all in
! <structname>pg_autovacuum</structname> for any particular table, the
! corresponding values from <filename>postgresql.conf</filename> are used.
</para>
<para>
! There is not currently any support for making
! <structname>pg_autovacuum</structname> entries, except by doing
! manual <command>INSERT</>s into the catalog. This feature will be
! improved in future releases, and it is likely that the catalog
! definition will change.
</para>
- <caution>
- <para>
- The contents of the <structname>pg_autovacuum</structname> system
- catalog are currently not saved in database dumps created by the
- tools <application>pg_dump</> and <application>pg_dumpall</>. If
- you want to preserve them across a dump/reload cycle, make sure
- you dump the catalog manually.
- </para>
- </caution>
-
<para>
When multiple workers are running, the cost limit is
<quote>balanced</quote> among all the running workers, so that the
--- 604,657 ----
<para>
The default thresholds and scale factors are taken from
<filename>postgresql.conf</filename>, but it is possible to override them
! on a table-by-table basis by specifying options in the system catalog column
<link
! linkend="catalog-pg-class"><structname>pg_class</>.<structfield>reloptions</></link>.
! If there is options in <structname>pg_class</>.<structfield>reloptions</>
! for a particular table, the settings it specifies are applied; otherwise the
! global settings are used. See <xref linkend="runtime-config-autovacuum"> for
! more details on the global settings.
</para>
<para>
! Besides the base threshold values and scale factors, there are six
! more autovacuum parameters that can be set for each table in
! <structname>pg_class</structname>.<structfield>reloptions</>.
! The first, <literal>autovacuum_enabled</>,
can be set to <literal>false</literal> to instruct the autovacuum daemon
to skip that particular table entirely. In this case
autovacuum will only touch the table if it must do so
to prevent transaction ID wraparound.
The next two parameters, the vacuum cost delay
! (<literal>autovacuum_vac_cost_delay</literal>) and the vacuum cost limit
! (<literal>autovacuum_vac_cost_limit</literal>), are used to set
! table-specific values for the
<xref linkend="runtime-config-resource-vacuum-cost" endterm="runtime-config-resource-vacuum-cost-title">
feature.
! The last three parameters, (<literal>autovacuum_freeze_min_age</literal>),
! (<literal>autovacuum_freeze_max_age</literal> and
! <literal>autovacuum_freeze_table_age</literal>), are used to set
! table-specific values for <xref linkend="guc-vacuum-freeze-min-age">,
! <xref linkend="guc-autovacuum-freeze-max-age"> and
! <xref linkend="guc-vacuum-freeze-table-age"> respectively.
</para>
<para>
! If any of the autovacuum-specific values in
! <structname>pg_class</structname>.<structfield>reloptions</>
! are not set, the corresponding values from
! <filename>postgresql.conf</filename> are used.
</para>
<para>
! The <literal>WITH</> clause can specify autovacuum-specific parameters for
! tables while creating them. Similarly, <literal>RESET</> can be used to reset
! autovacuum parameters to their defaults and <literal>SET</> can be used to
! add new autovacuum parameters. These parameters are documented in <xref
! linkend="SQL-CREATETABLE-relation-parameters"
! endterm="SQL-CREATETABLE-relation-parameters-title">.
</para>
<para>
When multiple workers are running, the cost limit is
<quote>balanced</quote> among all the running workers, so that the
Index: doc/src/sgml/ref/alter_index.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/ref/alter_index.sgml,v
retrieving revision 1.14
diff -c -p -r1.14 alter_index.sgml
*** doc/src/sgml/ref/alter_index.sgml 14 Nov 2008 10:22:45 -0000 1.14
--- doc/src/sgml/ref/alter_index.sgml 19 Dec 2008 23:50:39 -0000
*************** ALTER INDEX <replaceable class="PARAMETE
*** 75,80 ****
--- 75,90 ----
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><replaceable class="PARAMETER">value</replaceable></term>
+ <listitem>
+ <para>
+ The new value for a storage parameter.
+ This might be a number or a word depending on the parameter.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] )</literal></term>
<listitem>
Index: doc/src/sgml/ref/create_index.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/ref/create_index.sgml,v
retrieving revision 1.69
diff -c -p -r1.69 create_index.sgml
*** doc/src/sgml/ref/create_index.sgml 14 Nov 2008 10:22:46 -0000 1.69
--- doc/src/sgml/ref/create_index.sgml 19 Dec 2008 23:50:39 -0000
*************** CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ]
*** 231,237 ****
<listitem>
<para>
The name of an index-method-specific storage parameter. See
! below for details.
</para>
</listitem>
</varlistentry>
--- 231,248 ----
<listitem>
<para>
The name of an index-method-specific storage parameter. See
! <xref linkend="SQL-CREATEINDEX-storage-parameters" endterm="SQL-CREATEINDEX-storage-parameters-title">
! for details.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><replaceable class="PARAMETER">value</replaceable></term>
! <listitem>
! <para>
! The new value for a storage parameter.
! This might be a number or a word depending on the parameter.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/ref/create_table.sgml
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/doc/src/sgml/ref/create_table.sgml,v
retrieving revision 1.111
diff -c -p -r1.111 create_table.sgml
*** doc/src/sgml/ref/create_table.sgml 14 Nov 2008 10:22:46 -0000 1.111
--- doc/src/sgml/ref/create_table.sgml 19 Dec 2008 23:50:39 -0000
*************** and <replaceable class="PARAMETER">table
*** 690,703 ****
for tables, and for indexes associated with a <literal>UNIQUE</literal> or
<literal>PRIMARY KEY</literal> constraint. Storage parameters for
indexes are documented in <xref linkend="SQL-CREATEINDEX"
! endterm="sql-createindex-title">. The only storage parameter currently
! available for tables is:
</para>
<variablelist>
<varlistentry>
! <term><literal>FILLFACTOR</></term>
<listitem>
<para>
The fillfactor for a table is a percentage between 10 and 100.
--- 690,703 ----
for tables, and for indexes associated with a <literal>UNIQUE</literal> or
<literal>PRIMARY KEY</literal> constraint. Storage parameters for
indexes are documented in <xref linkend="SQL-CREATEINDEX"
! endterm="sql-createindex-title">. The storage parameters currently
! available for tables are:
</para>
<variablelist>
<varlistentry>
! <term><literal>FILLFACTOR</> (<type>integer</>)</term>
<listitem>
<para>
The fillfactor for a table is a percentage between 10 and 100.
*************** and <replaceable class="PARAMETER">table
*** 714,719 ****
--- 714,833 ----
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>AUTOVACUUM_ENABLED</> (<type>boolean</>)</term>
+ <listitem>
+ <para>
+ Enables or disables the autovacuum daemon on a particular table.
+ If true, the autovacuum daemon will initiate a <command>VACUUM</> operation
+ on a particular table when the number of updated or deleted tuples exceeds
+ <literal>autovacuum_vac_threshold</> plus
+ <literal>autovacuum_vac_scale_factor</> times the number of live tuples
+ currently estimated to be in the relation.
+ Similarly, it will initiate an <command>ANALYZE</> operation when the
+ number of inserted, updated or deleted tuples exceeds
+ <literal>autovacuum_anl_threshold</> plus
+ <literal>autovacuum_anl_scale_factor</> times the number of live tuples
+ currently estimated to be in the relation.
+ If false, this table will not be autovacuumed, except to prevent
+ transaction Id wraparound. See <xref linkend="vacuum-for-wraparound"> for
+ more about wraparound prevention.
+ Observe that this variable inherits its value from the <xref
+ linkend="guc-autovacuum">.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_VACUUM_THRESHOLD</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Minimum number of updated or deleted tuples before initiate a
+ <command>VACUUM</> operation on a particular table.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_VACUUM_SCALE_FACTOR</> (<type>float4</>)</term>
+ <listitem>
+ <para>
+ Multiplier for <structfield>reltuples</> to add to
+ <literal>autovacuum_vac_threshold</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_ANALYZE_THRESHOLD</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Minimum number of inserted, updated, or deleted tuples before initiate an
+ <command>ANALYZE</> operation on a particular table.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_ANALYZE_SCALE_FACTOR</> (<type>float4</>)</term>
+ <listitem>
+ <para>
+ Multiplier for <structfield>reltuples</> to add to
+ <literal>autovacuum_anl_threshold</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_VACUUM_COST_DELAY</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-autovacuum-vacuum-cost-delay"> parameter. A
+ <literal>-1</> (or indeed any negative value) indicates that the
+ system-wide default (<varname>autovacuum_vacuum_cost_delay</>) should be
+ used for this particular value.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_VACUUM_COST_LIMIT</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-autovacuum-vacuum-cost-limit"> parameter. A
+ <literal>-1</> (or indeed any negative value) indicates that the
+ system-wide default (<varname>autovacuum_vacuum_cost_limit</>) should be
+ used for this particular value.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_FREEZE_MIN_AGE</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-vacuum-freeze-min-age"> parameter. Also,
+ autovacuum will ignore attempts to set a per-table
+ <literal>autovacuum_freeze_min_age</> larger than the half system-wide
+ <xref linkend="guc-autovacuum-freeze-max-age"> setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AUTOVACUUM_FREEZE_MAX_AGE</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-autovacuum-freeze-max-age"> parameter. Also,
+ autovacuum will ignore attempts to set a per-table
+ <literal>autovacuum_freeze_max_age</> larger than the system-wide setting
+ (it can only be set smaller). Note that while you can set
+ <literal>autovacuum_freeze_max_age</> very small, or even zero, this is
+ usually unwise since it will force frequent vacuuming.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect2>
Index: src/backend/access/common/reloptions.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/access/common/reloptions.c,v
retrieving revision 1.18
diff -c -p -r1.18 reloptions.c
*** src/backend/access/common/reloptions.c 12 Jan 2009 21:02:14 -0000 1.18
--- src/backend/access/common/reloptions.c 23 Jan 2009 00:07:43 -0000
***************
*** 48,53 ****
--- 48,61 ----
static relopt_bool boolRelOpts[] =
{
+ {
+ {
+ "autovacuum_enabled",
+ "Enables autovacuum in this relation",
+ RELOPT_KIND_HEAP
+ },
+ true
+ },
/* list terminator */
{ { NULL } }
};
*************** static relopt_int intRelOpts[] =
*** 86,97 ****
--- 94,169 ----
},
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
+ },
/* 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 } }
};
*************** untransformRelOptions(Datum options)
*** 558,563 ****
--- 630,681 ----
return result;
}
+ /*
+ * Extract reloptions from a pg_class tuple.
+ *
+ * This is a very low-level routine, expected to be used by relcache code only.
+ * For other uses, consider grabbing the pointer from the relcache entry
+ * instead.
+ *
+ * tupdesc is pg_class' tuple descriptor. amoptions is the amoptions regproc
+ * in the case of the tuple corresponding to an index, or InvalidOid otherwise.
+ */
+ bytea *
+ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions)
+ {
+ bytea *options;
+ bool isnull;
+ Datum datum;
+ Form_pg_class classForm;
+
+ datum = fastgetattr(tuple,
+ Anum_pg_class_reloptions,
+ tupdesc,
+ &isnull);
+ if (isnull)
+ return NULL;
+
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+
+ /* Parse into appropriate format; don't error out here */
+ switch (classForm->relkind)
+ {
+ case RELKIND_RELATION:
+ case RELKIND_TOASTVALUE:
+ case RELKIND_UNCATALOGED:
+ options = heap_reloptions(classForm->relkind, datum, false);
+ break;
+ case RELKIND_INDEX:
+ options = index_reloptions(amoptions, datum, false);
+ break;
+ default:
+ Assert(false); /* can't get here */
+ options = NULL; /* keep compiler quiet */
+ break;
+ }
+
+ return options;
+ }
/*
* Interpret reloptions that are given in text-array format.
*************** fillRelOptions(void *rdopts, Size basesi
*** 868,874 ****
/*
! * Option parser for anything that uses StdRdOptions (i.e. fillfactor only)
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
--- 986,993 ----
/*
! * Option parser for anything that uses StdRdOptions (i.e. fillfactor and
! * autovacuum)
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
*************** default_reloptions(Datum reloptions, boo
*** 877,883 ****
StdRdOptions *rdopts;
int numoptions;
relopt_parse_elt tab[] = {
! {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
--- 996,1020 ----
StdRdOptions *rdopts;
int numoptions;
relopt_parse_elt tab[] = {
! {"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_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);
Index: src/backend/catalog/Makefile
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.68
diff -c -p -r1.68 Makefile
*** src/backend/catalog/Makefile 19 Dec 2008 16:25:16 -0000 1.68
--- src/backend/catalog/Makefile 29 Dec 2008 15:03:11 -0000
*************** all: $(BKIFILES)
*** 26,32 ****
# 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_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 \
--- 26,32 ----
# 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_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 \
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.92
diff -c -p -r1.92 autovacuum.c
*** src/backend/postmaster/autovacuum.c 16 Jan 2009 13:27:24 -0000 1.92
--- src/backend/postmaster/autovacuum.c 23 Jan 2009 15:56:56 -0000
***************
*** 69,80 ****
#include "access/genam.h"
#include "access/heapam.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"
--- 69,80 ----
#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_database.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
***************
*** 88,93 ****
--- 88,94 ----
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
+ #include "storage/lmgr.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
*************** typedef struct av_relation
*** 165,177 ****
{
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
} 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;
--- 166,179 ----
{
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
+ 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;
bool at_dovacuum;
bool at_doanalyze;
int at_freeze_min_age;
*************** static void autovac_balance_cost(void);
*** 282,297 ****
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,
Form_pg_class classForm,
! 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 PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
PgStat_StatDBEntry *shared,
PgStat_StatDBEntry *dbentry);
--- 284,300 ----
static void do_autovacuum(void);
static void FreeWorkerInfo(int code, Datum arg);
! 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);
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
! 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);
*************** get_database_list(void)
*** 1816,1823 ****
static void
do_autovacuum(void)
{
! Relation classRel,
! avRel;
HeapTuple tuple;
HeapScanDesc relScan;
Form_pg_database dbForm;
--- 1819,1825 ----
static void
do_autovacuum(void)
{
! Relation classRel;
HeapTuple tuple;
HeapScanDesc relScan;
Form_pg_database dbForm;
*************** do_autovacuum(void)
*** 1829,1834 ****
--- 1831,1837 ----
PgStat_StatDBEntry *dbentry;
BufferAccessStrategy bstrategy;
ScanKeyData key;
+ TupleDesc pg_class_desc;
/*
* StartTransactionCommand and CommitTransactionCommand will automatically
*************** do_autovacuum(void)
*** 1890,1896 ****
shared = pgstat_fetch_stat_dbentry(InvalidOid);
classRel = heap_open(RelationRelationId, AccessShareLock);
! avRel = heap_open(AutovacuumRelationId, AccessShareLock);
/* create hash table for toast <-> main relid mapping */
MemSet(&ctl, 0, sizeof(ctl));
--- 1893,1901 ----
shared = pgstat_fetch_stat_dbentry(InvalidOid);
classRel = heap_open(RelationRelationId, 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));
*************** do_autovacuum(void)
*** 1909,1917 ****
* 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
--- 1914,1922 ----
* 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_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
*************** do_autovacuum(void)
*** 1931,1939 ****
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;
--- 1936,1943 ----
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
! AutoVacOpts *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
*************** do_autovacuum(void)
*** 1942,1958 ****
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 */
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
shared, dbentry);
/* Check if it needs vacuum or analyze */
! relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/*
--- 1946,1958 ----
relid = HeapTupleGetOid(tuple);
! /* 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, relopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/*
*************** do_autovacuum(void)
*** 1998,2004 ****
}
else
{
! /* Plain relations that need work are added to table_oids */
if (dovacuum || doanalyze)
table_oids = lappend_oid(table_oids, relid);
--- 1998,2004 ----
}
else
{
! /* relations that need work are added to table_oids */
if (dovacuum || doanalyze)
table_oids = lappend_oid(table_oids, relid);
*************** do_autovacuum(void)
*** 2020,2031 ****
{
/* hash_search already filled in the key */
hentry->ar_relid = relid;
}
}
}
-
- if (HeapTupleIsValid(avTup))
- heap_freetuple(avTup);
}
heap_endscan(relScan);
--- 2020,2035 ----
{
/* hash_search already filled in the key */
hentry->ar_relid = relid;
+ hentry->ar_reloptions = NULL;
+ if (relopts != NULL)
+ {
+ hentry->ar_reloptions = palloc(sizeof(AutoVacOpts));
+ memcpy(hentry->ar_reloptions, relopts,
+ sizeof(AutoVacOpts));
+ }
}
}
}
}
heap_endscan(relScan);
*************** do_autovacuum(void)
*** 2040,2049 ****
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;
--- 2044,2052 ----
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
+ AutoVacOpts *relopts = NULL;
bool dovacuum;
bool doanalyze;
bool wraparound;
*************** do_autovacuum(void)
*** 2057,2073 ****
relid = HeapTupleGetOid(tuple);
! /* Fetch the pg_autovacuum tuple for this rel */
! 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 */
--- 2060,2085 ----
relid = HeapTupleGetOid(tuple);
! /*
! * 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;
! hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
! if (found)
! 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, relopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/* ignore analyze for toast tables */
*************** do_autovacuum(void)
*** 2076,2082 ****
}
heap_endscan(relScan);
- heap_close(avRel, AccessShareLock);
heap_close(classRel, AccessShareLock);
/*
--- 2088,2093 ----
*************** do_autovacuum(void)
*** 2163,2172 ****
* condition is not closed but it is very small.
*/
MemoryContextSwitchTo(AutovacMemCxt);
! tab = table_recheck_autovac(relid, table_toast_map);
if (tab == NULL)
{
! /* someone else vacuumed the table */
LWLockRelease(AutovacuumScheduleLock);
continue;
}
--- 2174,2183 ----
* condition is not closed but it is very small.
*/
MemoryContextSwitchTo(AutovacMemCxt);
! tab = table_recheck_autovac(relid, table_toast_map, pg_class_desc);
if (tab == NULL)
{
! /* someone else vacuumed the table, or it went away */
LWLockRelease(AutovacuumScheduleLock);
continue;
}
*************** deleted:
*** 2292,2343 ****
}
/*
- * 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.
- *
- * 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
- get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
- HTAB *table_toast_map)
- {
- ScanKeyData entry[1];
- SysScanDesc avScan;
- HeapTuple avTup;
-
- ScanKeyInit(&entry[0],
- Anum_pg_autovacuum_vacrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relid));
-
- 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);
- }
-
- return avTup;
- }
-
- /*
* get_pgstat_tabentry_relid
*
* Fetch the pgstat entry of a table, either local to a database or shared.
--- 2303,2308 ----
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 2362,2367 ****
--- 2327,2358 ----
}
/*
+ * extract_autovac_opts
+ *
+ * Given a relation's pg_class tuple, return the AutoVacOpts portion of
+ * reloptions, if set; otherwise, return NULL.
+ */
+ AutoVacOpts *
+ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
+ {
+ bytea *relopts;
+ AutoVacOpts *av;
+
+ Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
+ ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
+
+ 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 av;
+ }
+
+ /*
* table_recheck_autovac
*
* Recheck whether a table still needs vacuum or analyze. Return value is a
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 2370,2382 ****
* 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)
{
- Form_pg_autovacuum avForm = NULL;
Form_pg_class classForm;
HeapTuple classTup;
- HeapTuple avTup;
- Relation avRel;
bool dovacuum;
bool doanalyze;
autovac_table *tab = NULL;
--- 2361,2371 ----
* 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,
! TupleDesc pg_class_desc)
{
Form_pg_class classForm;
HeapTuple classTup;
bool dovacuum;
bool doanalyze;
autovac_table *tab = NULL;
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2384,2389 ****
--- 2373,2379 ----
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
bool wraparound;
+ AutoVacOpts *avopts;
/* use fresh stats */
autovac_refresh_stats();
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2399,2421 ****
return NULL;
classForm = (Form_pg_class) GETSTRUCT(classTup);
! /*
! * Fetch the pg_autovacuum entry, if any. For a toast table, also try the
! * main rel's pg_autovacuum entry if there isn't one for the TOAST table
! * itself.
! */
! avRel = heap_open(AutovacuumRelationId, AccessShareLock);
! avTup = get_pg_autovacuum_tuple_relid(avRel, relid,
! classForm->relkind == RELKIND_TOASTVALUE ? table_toast_map : NULL);
! if (HeapTupleIsValid(avTup))
! avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
/* fetch the pgstat table entry */
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 */
--- 2389,2415 ----
return NULL;
classForm = (Form_pg_class) GETSTRUCT(classTup);
! /*
! * 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.
! */
! avopts = extract_autovac_opts(classTup, pg_class_desc);
! if (classForm->relkind == RELKIND_TOASTVALUE &&
! avopts == NULL && table_toast_map != NULL)
! {
! av_relation *hentry;
! bool found;
! hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
! if (found)
! avopts = hentry->ar_reloptions;
! }
/* fetch the pgstat table entry */
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
shared, dbentry);
! relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/* ignore ANALYZE for toast tables */
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2432,2476 ****
/*
* 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.
! */
! if (avForm != NULL)
! {
! 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;
}
else
{
! vac_cost_limit = (autovacuum_vac_cost_limit > 0) ?
! autovacuum_vac_cost_limit : VacuumCostLimit;
!
! vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
autovacuum_vac_cost_delay : VacuumCostDelay;
!
freeze_min_age = default_freeze_min_age;
-
freeze_table_age = default_freeze_table_age;
}
tab = palloc(sizeof(autovac_table));
- tab->at_relid = relid;
tab->at_dovacuum = dovacuum;
tab->at_doanalyze = doanalyze;
tab->at_freeze_min_age = freeze_min_age;
--- 2426,2455 ----
/*
* Calculate the vacuum cost parameters and the minimum freeze age. If
! * there is an option in pg_class.reloptions, use it; 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 (avopts)
! {
! 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
{
! /* -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;
freeze_min_age = default_freeze_min_age;
freeze_table_age = default_freeze_table_age;
}
tab = palloc(sizeof(autovac_table));
tab->at_dovacuum = dovacuum;
tab->at_doanalyze = doanalyze;
tab->at_freeze_min_age = freeze_min_age;
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2478,2491 ****
tab->at_vacuum_cost_limit = vac_cost_limit;
tab->at_vacuum_cost_delay = vac_cost_delay;
tab->at_wraparound = wraparound;
- tab->at_relname = NULL;
tab->at_nspname = NULL;
tab->at_datname = NULL;
}
- heap_close(avRel, AccessShareLock);
- if (HeapTupleIsValid(avTup))
- heap_freetuple(avTup);
heap_freetuple(classTup);
return tab;
--- 2457,2466 ----
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2496,2503 ****
*
* 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.
*
* A table needs to be vacuumed if the number of dead tuples exceeds a
* threshold. This threshold is calculated as
--- 2471,2482 ----
*
* 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.
! *
! * "rel" is the relation to be checked, already opened and AccessShare-locked;
! * relopts is NULL when the relation is a regular table, and the AutoVacOpts
! * options from the main table in the case of a toast table (NULL if it doesn't
! * have any); 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
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2513,2531 ****
* 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
* 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
* autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor
! * 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,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
/* output params below */
--- 2492,2510 ----
* We also force vacuum if the table's relfrozenxid is more than freeze_max_age
* transactions back.
*
! * 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
* autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor
! * value < 0 is substituted with the value of
* autovacuum_vacuum_scale_factor GUC variable. Ditto for analyze.
*/
static void
relation_needs_vacanalyze(Oid relid,
! AutoVacOpts *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
/* output params below */
*************** relation_needs_vacanalyze(Oid relid,
*** 2534,2542 ****
bool *wraparound)
{
bool force_vacuum;
float4 reltuples; /* pg_class.reltuples */
! /* constants from pg_autovacuum or GUC variables */
int vac_base_thresh,
anl_base_thresh;
float4 vac_scale_factor,
--- 2513,2522 ----
bool *wraparound)
{
bool force_vacuum;
+ bool av_enabled;
float4 reltuples; /* pg_class.reltuples */
! /* constants from reloptions or GUC variables */
int vac_base_thresh,
anl_base_thresh;
float4 vac_scale_factor,
*************** relation_needs_vacanalyze(Oid relid,
*** 2554,2593 ****
int freeze_max_age;
TransactionId xidForceLimit;
- AssertArg(classForm != NULL);
- 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.
! */
! if (avForm != NULL)
! {
! 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;
}
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;
}
/* Force vacuum if table is at risk of wraparound */
--- 2534,2562 ----
int freeze_max_age;
TransactionId xidForceLimit;
/*
! * 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 (relopts)
! {
! 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 */
*************** relation_needs_vacanalyze(Oid relid,
*** 2599,2609 ****
xidForceLimit));
*wraparound = force_vacuum;
! /* User disabled it in pg_autovacuum? (But ignore if at risk) */
! if (avForm && !avForm->enabled && !force_vacuum)
{
*doanalyze = false;
*dovacuum = false;
return;
}
--- 2568,2579 ----
xidForceLimit));
*wraparound = force_vacuum;
! /* User disabled it in pg_class.reloptions? (But ignore if at risk) */
! if (!force_vacuum && !av_enabled)
{
*doanalyze = false;
*dovacuum = false;
+
return;
}
*************** relation_needs_vacanalyze(Oid relid,
*** 2644,2649 ****
--- 2614,2633 ----
/* ANALYZE refuses to work with pg_statistics */
if (relid == StatisticRelationId)
*doanalyze = false;
+
+ if (*doanalyze || *dovacuum)
+ {
+ elog(LOG, "parameters used for %s (%s) -- freeze max age: %d\n"
+ "vac scale: %f, thresh: %d; do it: %s\n"
+ "anl scale: %f, thresh: %d; do it: %s",
+ NameStr(classForm->relname),
+ relopts ? "relopts" : "defaults",
+ freeze_max_age,
+ vac_scale_factor, vac_base_thresh,
+ *dovacuum ? "yes" : "no",
+ anl_scale_factor, anl_base_thresh,
+ *doanalyze ? "yes" : "no");
+ }
}
/*
*************** autovacuum_do_vac_analyze(autovac_table
*** 2672,2678 ****
/* Let pgstat know what we're doing */
autovac_report_activity(tab);
! vacuum(&vacstmt, tab->at_relid, false, bstrategy, tab->at_wraparound, true);
}
/*
--- 2656,2663 ----
/* Let pgstat know what we're doing */
autovac_report_activity(tab);
! vacuum(&vacstmt, tab->at_relid, false, bstrategy,
! tab->at_wraparound, true);
}
/*
Index: src/backend/utils/cache/relcache.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/utils/cache/relcache.c,v
retrieving revision 1.282
diff -c -p -r1.282 relcache.c
*** src/backend/utils/cache/relcache.c 22 Jan 2009 20:16:06 -0000 1.282
--- src/backend/utils/cache/relcache.c 23 Jan 2009 15:30:30 -0000
*************** AllocateRelationDesc(Relation relation,
*** 351,358 ****
static void
RelationParseRelOptions(Relation relation, HeapTuple tuple)
{
- Datum datum;
- bool isnull;
bytea *options;
relation->rd_options = NULL;
--- 351,356 ----
*************** RelationParseRelOptions(Relation relatio
*** 374,404 ****
* we might not have any other for pg_class yet (consider executing this
* code for pg_class itself)
*/
! datum = fastgetattr(tuple,
! Anum_pg_class_reloptions,
! GetPgClassDescriptor(),
! &isnull);
! if (isnull)
! return;
!
! /* Parse into appropriate format; don't error out here */
! switch (relation->rd_rel->relkind)
! {
! case RELKIND_RELATION:
! case RELKIND_TOASTVALUE:
! case RELKIND_UNCATALOGED:
! options = heap_reloptions(relation->rd_rel->relkind, datum,
! false);
! break;
! case RELKIND_INDEX:
! options = index_reloptions(relation->rd_am->amoptions, datum,
! false);
! break;
! default:
! Assert(false); /* can't get here */
! options = NULL; /* keep compiler quiet */
! break;
! }
/* Copy parsed data into CacheMemoryContext */
if (options)
--- 372,381 ----
* we might not have any other for pg_class yet (consider executing this
* code for pg_class itself)
*/
! options = extractRelOptions(tuple,
! GetPgClassDescriptor(),
! relation->rd_rel->relkind == RELKIND_INDEX ?
! relation->rd_am->amoptions : InvalidOid);
/* Copy parsed data into CacheMemoryContext */
if (options)
Index: src/include/access/reloptions.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/access/reloptions.h,v
retrieving revision 1.10
diff -c -p -r1.10 reloptions.h
*** src/include/access/reloptions.h 12 Jan 2009 21:02:15 -0000 1.10
--- src/include/access/reloptions.h 23 Jan 2009 00:07:44 -0000
***************
*** 18,23 ****
--- 18,24 ----
#ifndef RELOPTIONS_H
#define RELOPTIONS_H
+ #include "access/htup.h"
#include "nodes/pg_list.h"
/* types supported by reloptions */
*************** extern void add_string_reloption(int kin
*** 241,246 ****
--- 242,249 ----
extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool ignoreOids, bool isReset);
extern List *untransformRelOptions(Datum options);
+ extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
+ Oid amoptions);
extern relopt_value *parseRelOptions(Datum options, bool validate,
relopt_kind kind, int *numrelopts);
extern void *allocateReloptStruct(Size base, relopt_value *options,
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/catalog/indexing.h,v
retrieving revision 1.106
diff -c -p -r1.106 indexing.h
*** src/include/catalog/indexing.h 22 Jan 2009 20:16:08 -0000 1.106
--- src/include/catalog/indexing.h 23 Jan 2009 15:30:30 -0000
*************** DECLARE_UNIQUE_INDEX(pg_auth_members_rol
*** 97,105 ****
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));
--- 97,102 ----
Index: src/include/utils/rel.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/utils/rel.h,v
retrieving revision 1.111
diff -c -p -r1.111 rel.h
*** src/include/utils/rel.h 1 Jan 2009 17:24:02 -0000 1.111
--- src/include/utils/rel.h 23 Jan 2009 00:46:56 -0000
*************** typedef struct RelationData
*** 214,223 ****
--- 214,239 ----
* 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
Index: src/test/regress/expected/sanity_check.out
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/test/regress/expected/sanity_check.out,v
retrieving revision 1.38
diff -c -p -r1.38 sanity_check.out
*** src/test/regress/expected/sanity_check.out 19 Dec 2008 16:25:19 -0000 1.38
--- src/test/regress/expected/sanity_check.out 29 Dec 2008 15:04:14 -0000
*************** SELECT relname, relhasindex
*** 90,96 ****
pg_attribute | t
pg_auth_members | t
pg_authid | t
- pg_autovacuum | t
pg_cast | t
pg_class | t
pg_constraint | t
--- 90,95 ----
*************** SELECT relname, relhasindex
*** 152,158 ****
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (141 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- 151,157 ----
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (140 rows)
--
-- another sanity check: every system catalog that has OIDs should have
Alvaro Herrera escribi�:
Here's my proposed patch. There is a bug in the handling of TOAST
tables; I'm sending this as a WIP to add it to the commitfest status
page for this patch.
Sorry, that was a really stupid bug.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Attachments:
reloptions-autovacuum-2.1.patchtext/x-diff; charset=us-asciiDownload
diff -u src/backend/postmaster/autovacuum.c src/backend/postmaster/autovacuum.c
--- src/backend/postmaster/autovacuum.c 23 Jan 2009 15:56:56 -0000
+++ src/backend/postmaster/autovacuum.c 23 Jan 2009 16:49:37 -0000
@@ -1900,7 +1900,7 @@
/* 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",
So here's what looks like a committable patch.
Note to self: remember to remove src/include/catalog/pg_autovacuum.h and
to bump catversion.
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Attachments:
reloptions-autovacuum-4.1.patchtext/x-diff; charset=us-asciiDownload
Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.194
diff -c -p -r2.194 catalogs.sgml
*** doc/src/sgml/catalogs.sgml 4 Feb 2009 21:30:41 -0000 2.194
--- doc/src/sgml/catalogs.sgml 5 Feb 2009 18:32:40 -0000
***************
*** 89,99 ****
</row>
<row>
- <entry><link linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</structname></link></entry>
- <entry>per-relation autovacuum configuration parameters</entry>
- </row>
-
- <row>
<entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
<entry>casts (data type conversions)</entry>
</row>
--- 89,94 ----
***************
*** 1256,1433 ****
</sect1>
- <sect1 id="catalog-pg-autovacuum">
- <title><structname>pg_autovacuum</structname></title>
-
- <indexterm zone="catalog-pg-autovacuum">
- <primary>pg_autovacuum</primary>
- </indexterm>
-
- <indexterm zone="catalog-pg-autovacuum">
- <primary>autovacuum</primary>
- <secondary>table-specific configuration</secondary>
- </indexterm>
-
- <para>
- The catalog <structname>pg_autovacuum</structname> stores optional
- per-relation configuration parameters for the autovacuum daemon.
- If there is an entry here for a particular relation, the given
- parameters will be used for autovacuuming that table. If no entry
- is present, the system-wide defaults will be used. For more information
- about the autovacuum daemon, see <xref linkend="autovacuum">.
- </para>
-
- <note>
- <para>
- It is likely that <structname>pg_autovacuum</structname> will disappear
- in a future release, with the information instead being kept in
- <structname>pg_class</>.<structfield>reloptions</> entries.
- </para>
- </note>
-
- <table>
- <title><structname>pg_autovacuum</> Columns</title>
-
- <tgroup cols="4">
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Type</entry>
- <entry>References</entry>
- <entry>Description</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry><structfield>vacrelid</structfield></entry>
- <entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
- <entry>The table this entry is for</entry>
- </row>
-
- <row>
- <entry><structfield>enabled</structfield></entry>
- <entry><type>bool</type></entry>
- <entry></entry>
- <entry>If false, this table will not be autovacuumed, except
- to prevent transaction ID wraparound</entry>
- </row>
-
- <row>
- <entry><structfield>vac_base_thresh</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Minimum number of modified tuples before vacuum</entry>
- </row>
-
- <row>
- <entry><structfield>vac_scale_factor</structfield></entry>
- <entry><type>float4</type></entry>
- <entry></entry>
- <entry>Multiplier for <structfield>reltuples</> to add to
- <structfield>vac_base_thresh</></entry>
- </row>
-
- <row>
- <entry><structfield>anl_base_thresh</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Minimum number of modified tuples before analyze</entry>
- </row>
-
- <row>
- <entry><structfield>anl_scale_factor</structfield></entry>
- <entry><type>float4</type></entry>
- <entry></entry>
- <entry>Multiplier for <structfield>reltuples</> to add to
- <structfield>anl_base_thresh</></entry>
- </row>
-
- <row>
- <entry><structfield>vac_cost_delay</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_cost_delay</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>vac_cost_limit</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_cost_limit</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_min_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_freeze_min_age</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_max_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>autovacuum_freeze_max_age</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_table_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_freeze_table_age</> parameter</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- The autovacuum daemon will initiate a <command>VACUUM</> operation
- on a particular table when the number of updated or deleted tuples
- exceeds <structfield>vac_base_thresh</structfield> plus
- <structfield>vac_scale_factor</structfield> times the number of
- live tuples currently estimated to be in the relation.
- Similarly, it will initiate an <command>ANALYZE</> operation
- when the number of inserted, updated or deleted tuples
- exceeds <structfield>anl_base_thresh</structfield> plus
- <structfield>anl_scale_factor</structfield> times the number of
- live tuples currently estimated to be in the relation.
- </para>
-
- <para>
- Also, the autovacuum daemon will perform a <command>VACUUM</> operation
- to prevent transaction ID wraparound if the table's
- <structname>pg_class</>.<structfield>relfrozenxid</> field attains an age
- of more than <structfield>freeze_max_age</> transactions, whether the table
- has been changed or not, even if
- <structname>pg_autovacuum</>.<structfield>enabled</> is set to
- <literal>false</> for it. The system will launch autovacuum to perform
- such <command>VACUUM</>s even if autovacuum is otherwise disabled.
- See <xref linkend="vacuum-for-wraparound"> for more about wraparound
- prevention.
- </para>
-
- <para>
- Any of the numerical fields can contain <literal>-1</> (or indeed
- any negative value) to indicate that the system-wide default should
- be used for this particular value. Observe that the
- <structfield>vac_cost_delay</> variable inherits its default value from the
- <xref linkend="guc-autovacuum-vacuum-cost-delay"> configuration parameter,
- or from <xref linkend="guc-vacuum-cost-delay"> if the former is set to a
- negative value. The same applies to <structfield>vac_cost_limit</>.
- Also, autovacuum will ignore attempts to set a per-table
- <structfield>freeze_max_age</> larger than the system-wide setting (it can
- only be set smaller), and the <structfield>freeze_min_age</> value will be
- limited to half the system-wide <xref
- linkend="guc-autovacuum-freeze-max-age"> setting. Note that while you
- can set <structfield>freeze_max_age</> very small, or even zero, this
- is usually unwise since it will force frequent vacuuming.
- </para>
-
- </sect1>
-
-
<sect1 id="catalog-pg-cast">
<title><structname>pg_cast</structname></title>
--- 1251,1256 ----
Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.206
diff -c -p -r1.206 config.sgml
*** doc/src/sgml/config.sgml 16 Jan 2009 13:27:23 -0000 1.206
--- doc/src/sgml/config.sgml 29 Jan 2009 17:23:12 -0000
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3547,3554 ****
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3547,3554 ----
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3565,3572 ****
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3565,3572 ----
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3584,3591 ****
The default is 0.2 (20% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3584,3591 ----
The default is 0.2 (20% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3603,3610 ****
The default is 0.1 (10% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3603,3610 ----
The default is 0.1 (10% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3624,3631 ****
autovacuum is otherwise disabled.
The default is 200 million transactions.
This parameter can only be set at server start, but the setting
! can be reduced for individual tables by entries in
! <structname>pg_autovacuum</>.
For more information see <xref linkend="vacuum-for-wraparound">.
</para>
</listitem>
--- 3624,3631 ----
autovacuum is otherwise disabled.
The default is 200 million transactions.
This parameter can only be set at server start, but the setting
! can be reduced for individual tables by entries by
! changing storage parameters.
For more information see <xref linkend="vacuum-for-wraparound">.
</para>
</listitem>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3645,3652 ****
The default value is 20 milliseconds.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3645,3652 ----
The default value is 20 milliseconds.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3667,3674 ****
each worker never exceeds the limit on this variable.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3667,3674 ----
each worker never exceeds the limit on this variable.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/maintenance.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/maintenance.sgml,v
retrieving revision 1.89
diff -c -p -r1.89 maintenance.sgml
*** doc/src/sgml/maintenance.sgml 16 Jan 2009 13:27:23 -0000 1.89
--- doc/src/sgml/maintenance.sgml 5 Feb 2009 21:04:54 -0000
*************** HINT: Stop the postmaster and use a sta
*** 573,579 ****
<para>
Tables whose <structfield>relfrozenxid</> value is more than
<varname>autovacuum_freeze_max_age</> transactions old are always
! vacuumed. Otherwise, if the number of tuples obsoleted since the last
<command>VACUUM</command> exceeds the <quote>vacuum threshold</quote>, the
table is vacuumed. The vacuum threshold is defined as:
<programlisting>
--- 573,581 ----
<para>
Tables whose <structfield>relfrozenxid</> value is more than
<varname>autovacuum_freeze_max_age</> transactions old are always
! vacuumed (this also applies to those tables whose freeze max age has
! been modified via storage parameters; see below). Otherwise, if the
! number of tuples obsoleted since the last
<command>VACUUM</command> exceeds the <quote>vacuum threshold</quote>, the
table is vacuumed. The vacuum threshold is defined as:
<programlisting>
*************** analyze threshold = analyze base thresho
*** 604,669 ****
<para>
The default thresholds and scale factors are taken from
<filename>postgresql.conf</filename>, but it is possible to override them
! on a table-by-table basis by making entries in the system catalog
! <link
! linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</></link>.
! If a <structname>pg_autovacuum</structname> row exists for a particular
! table, the settings it specifies are applied; otherwise the global
! settings are used. See <xref linkend="runtime-config-autovacuum"> for
more details on the global settings.
</para>
<para>
! Besides the base threshold values and scale factors, there are five
! more parameters that can be set for each table in
! <structname>pg_autovacuum</structname>.
! The first, <structname>pg_autovacuum</>.<structfield>enabled</>,
can be set to <literal>false</literal> to instruct the autovacuum daemon
to skip that particular table entirely. In this case
autovacuum will only touch the table if it must do so
to prevent transaction ID wraparound.
! The next two parameters, the vacuum cost delay
! (<structname>pg_autovacuum</structname>.<structfield>vac_cost_delay</structfield>)
! and the vacuum cost limit
! (<structname>pg_autovacuum</structname>.<structfield>vac_cost_limit</structfield>),
! are used to set table-specific values for the
! <xref linkend="runtime-config-resource-vacuum-cost" endterm="runtime-config-resource-vacuum-cost-title">
feature.
! The last two parameters,
! (<structname>pg_autovacuum</structname>.<structfield>freeze_min_age</structfield>)
! and
! (<structname>pg_autovacuum</structname>.<structfield>freeze_max_age</structfield>),
! are used to set table-specific values for
! <xref linkend="guc-vacuum-freeze-min-age"> and
! <xref linkend="guc-autovacuum-freeze-max-age"> respectively.
</para>
<para>
! If any of the values in <structname>pg_autovacuum</structname>
! are set to a negative number, or if a row is not present at all in
! <structname>pg_autovacuum</structname> for any particular table, the
! corresponding values from <filename>postgresql.conf</filename> are used.
</para>
<para>
- There is not currently any support for making
- <structname>pg_autovacuum</structname> entries, except by doing
- manual <command>INSERT</>s into the catalog. This feature will be
- improved in future releases, and it is likely that the catalog
- definition will change.
- </para>
-
- <caution>
- <para>
- The contents of the <structname>pg_autovacuum</structname> system
- catalog are currently not saved in database dumps created by the
- tools <application>pg_dump</> and <application>pg_dumpall</>. If
- you want to preserve them across a dump/reload cycle, make sure
- you dump the catalog manually.
- </para>
- </caution>
-
- <para>
When multiple workers are running, the cost limit is
<quote>balanced</quote> among all the running workers, so that the
total impact on the system is the same, regardless of the number
--- 606,651 ----
<para>
The default thresholds and scale factors are taken from
<filename>postgresql.conf</filename>, but it is possible to override them
! on a table-by-table basis by specifying storage parameters. If a setting
! has been changed via storage parameters, that value is used; otherwise the
! global settings are used. See <xref linkend="runtime-config-autovacuum"> for
more details on the global settings.
</para>
<para>
! Besides the base threshold values and scale factors, there are six
! more autovacuum parameters that can be set for each table via
! storage parameters.
! The first parameter, <literal>autovacuum_enabled</>,
can be set to <literal>false</literal> to instruct the autovacuum daemon
to skip that particular table entirely. In this case
autovacuum will only touch the table if it must do so
to prevent transaction ID wraparound.
! The next two parameters,
! <literal>autovacuum_vac_cost_delay</literal> and
! <literal>autovacuum_vac_cost_limit</literal>, are used to set
! table-specific values for the
! <xref linkend="runtime-config-resource-vacuum-cost"
! endterm="runtime-config-resource-vacuum-cost-title">
feature.
! <literal>autovacuum_freeze_min_age</literal>,
! <literal>autovacuum_freeze_max_age</literal> and
! <literal>autovacuum_freeze_table_age</literal> are used to set
! values for <xref linkend="guc-vacuum-freeze-min-age">,
! <xref linkend="guc-autovacuum-freeze-max-age"> and
! <xref linkend="guc-vacuum-freeze-table-age"> respectively.
</para>
<para>
! The <literal>WITH</literal> clause of <xref linkend="sql-createtable">
! can be used to change autovacuum parameters on table creation; see
! <xref linkend="sql-createtable-storage-parameters"
! endterm="sql-createtable-storage-parameters-title"> for more information.
! They can be modified afterwards with the <literal>SET</literal> and
! <literal>RESET</literal> clauses of <xref linkend="sql-altertable">.
</para>
<para>
When multiple workers are running, the cost limit is
<quote>balanced</quote> among all the running workers, so that the
total impact on the system is the same, regardless of the number
Index: doc/src/sgml/ref/alter_index.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/alter_index.sgml,v
retrieving revision 1.14
diff -c -p -r1.14 alter_index.sgml
*** doc/src/sgml/ref/alter_index.sgml 14 Nov 2008 10:22:45 -0000 1.14
--- doc/src/sgml/ref/alter_index.sgml 29 Jan 2009 17:23:12 -0000
*************** ALTER INDEX <replaceable class="PARAMETE
*** 75,80 ****
--- 75,90 ----
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><replaceable class="PARAMETER">value</replaceable></term>
+ <listitem>
+ <para>
+ The new value for a storage parameter.
+ This might be a number or a word depending on the parameter.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] )</literal></term>
<listitem>
Index: doc/src/sgml/ref/create_table.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/create_table.sgml,v
retrieving revision 1.112
diff -c -p -r1.112 create_table.sgml
*** doc/src/sgml/ref/create_table.sgml 2 Feb 2009 19:31:38 -0000 1.112
--- doc/src/sgml/ref/create_table.sgml 5 Feb 2009 21:14:17 -0000
*************** and <replaceable class="PARAMETER">table
*** 697,703 ****
<variablelist>
<varlistentry>
! <term><literal>FILLFACTOR</></term>
<listitem>
<para>
The fillfactor for a table is a percentage between 10 and 100.
--- 697,703 ----
<variablelist>
<varlistentry>
! <term><literal>fillfactor</> (<type>integer</>)</term>
<listitem>
<para>
The fillfactor for a table is a percentage between 10 and 100.
*************** and <replaceable class="PARAMETER">table
*** 715,721 ****
</varlistentry>
<varlistentry>
! <term><literal>TOAST.FILLFACTOR</literal></term>
<listitem>
<para>
Same as above, for the supplementary storage table, if any; see
--- 715,721 ----
</varlistentry>
<varlistentry>
! <term><literal>toast.fillfactor</literal></term>
<listitem>
<para>
Same as above, for the supplementary storage table, if any; see
*************** and <replaceable class="PARAMETER">table
*** 724,729 ****
--- 724,846 ----
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>autovacuum_enabled</> (<type>boolean</>)</term>
+ <listitem>
+ <para>
+ Enables or disables the autovacuum daemon on a particular table.
+ If true, the autovacuum daemon will initiate a <command>VACUUM</> operation
+ on a particular table when the number of updated or deleted tuples exceeds
+ <literal>autovacuum_vac_threshold</> plus
+ <literal>autovacuum_vac_scale_factor</> times the number of live tuples
+ currently estimated to be in the relation.
+ Similarly, it will initiate an <command>ANALYZE</> operation when the
+ number of inserted, updated or deleted tuples exceeds
+ <literal>autovacuum_anl_threshold</> plus
+ <literal>autovacuum_anl_scale_factor</> times the number of live tuples
+ currently estimated to be in the relation.
+ If false, this table will not be autovacuumed, except to prevent
+ transaction Id wraparound. See <xref linkend="vacuum-for-wraparound"> for
+ more about wraparound prevention.
+ Observe that this variable inherits its value from the <xref
+ linkend="guc-autovacuum">.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_vacuum_threshold</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Minimum number of updated or deleted tuples before initiate a
+ <command>VACUUM</> operation on a particular table.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_vacuum_scale_factor</> (<type>float4</>)</term>
+ <listitem>
+ <para>
+ Multiplier for <structfield>reltuples</> to add to
+ <literal>autovacuum_vacuum_threshold</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_analyze_threshold</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Minimum number of inserted, updated, or deleted tuples before initiate an
+ <command>ANALYZE</> operation on a particular table.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_analyze_scale_factor</> (<type>float4</>)</term>
+ <listitem>
+ <para>
+ Multiplier for <structfield>reltuples</> to add to
+ <literal>autovacuum_analyze_threshold</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_vacuum_cost_delay</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-autovacuum-vacuum-cost-delay"> parameter.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_vacuum_cost_limit</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-autovacuum-vacuum-cost-limit"> parameter.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_freeze_min_age</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-vacuum-freeze-min-age"> parameter. Note that
+ autovacuum will ignore attempts to set a per-table
+ <literal>autovacuum_freeze_min_age</> larger than the half system-wide
+ <xref linkend="guc-autovacuum-freeze-max-age"> setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_freeze_max_age</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-autovacuum-freeze-max-age"> parameter. Note that
+ autovacuum will ignore attempts to set a per-table
+ <literal>autovacuum_freeze_max_age</> larger than the system-wide setting
+ (it can only be set smaller). Note that while you can set
+ <literal>autovacuum_freeze_max_age</> very small, or even zero, this is
+ usually unwise since it will force frequent vacuuming.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>autovacuum_freeze_table_age</literal> (<type>integer</type>)</term>
+ <listitem>
+ <para>
+ Custom <xref linkend="guc-vacuum-freeze-table-age"> parameter.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect2>
Index: src/backend/access/common/reloptions.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/common/reloptions.c,v
retrieving revision 1.20
diff -c -p -r1.20 reloptions.c
*** src/backend/access/common/reloptions.c 2 Feb 2009 19:31:38 -0000 1.20
--- src/backend/access/common/reloptions.c 5 Feb 2009 21:23:01 -0000
***************
*** 48,53 ****
--- 48,61 ----
static relopt_bool boolRelOpts[] =
{
+ {
+ {
+ "autovacuum_enabled",
+ "Enables autovacuum in this relation",
+ RELOPT_KIND_HEAP
+ },
+ true
+ },
/* list terminator */
{ { NULL } }
};
*************** static relopt_int intRelOpts[] =
*** 86,97 ****
--- 94,176 ----
},
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 } }
};
*************** fillRelOptions(void *rdopts, Size basesi
*** 973,979 ****
/*
! * Option parser for anything that uses StdRdOptions (i.e. fillfactor only)
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
--- 1052,1059 ----
/*
! * Option parser for anything that uses StdRdOptions (i.e. fillfactor and
! * autovacuum)
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
*************** default_reloptions(Datum reloptions, boo
*** 982,988 ****
StdRdOptions *rdopts;
int numoptions;
relopt_parse_elt tab[] = {
! {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
--- 1062,1088 ----
StdRdOptions *rdopts;
int numoptions;
relopt_parse_elt tab[] = {
! {"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);
Index: src/backend/catalog/Makefile
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.68
diff -c -p -r1.68 Makefile
*** src/backend/catalog/Makefile 19 Dec 2008 16:25:16 -0000 1.68
--- src/backend/catalog/Makefile 29 Jan 2009 17:23:12 -0000
*************** all: $(BKIFILES)
*** 26,32 ****
# 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_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 \
--- 26,32 ----
# 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_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 \
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.92
diff -c -p -r1.92 autovacuum.c
*** src/backend/postmaster/autovacuum.c 16 Jan 2009 13:27:24 -0000 1.92
--- src/backend/postmaster/autovacuum.c 5 Feb 2009 21:40:31 -0000
***************
*** 69,80 ****
#include "access/genam.h"
#include "access/heapam.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"
--- 69,80 ----
#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_database.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
***************
*** 88,93 ****
--- 88,94 ----
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
+ #include "storage/lmgr.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
*************** typedef struct av_relation
*** 165,177 ****
{
Oid ar_toastrelid; /* hash key - must be first */
Oid ar_relid;
} 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;
--- 166,180 ----
{
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;
bool at_dovacuum;
bool at_doanalyze;
int at_freeze_min_age;
*************** static void autovac_balance_cost(void);
*** 282,297 ****
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,
Form_pg_class classForm,
! 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 PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
PgStat_StatDBEntry *shared,
PgStat_StatDBEntry *dbentry);
--- 285,301 ----
static void do_autovacuum(void);
static void FreeWorkerInfo(int code, Datum arg);
! 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);
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
! 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);
*************** get_database_list(void)
*** 1816,1823 ****
static void
do_autovacuum(void)
{
! Relation classRel,
! avRel;
HeapTuple tuple;
HeapScanDesc relScan;
Form_pg_database dbForm;
--- 1820,1826 ----
static void
do_autovacuum(void)
{
! Relation classRel;
HeapTuple tuple;
HeapScanDesc relScan;
Form_pg_database dbForm;
*************** do_autovacuum(void)
*** 1829,1834 ****
--- 1832,1838 ----
PgStat_StatDBEntry *dbentry;
BufferAccessStrategy bstrategy;
ScanKeyData key;
+ TupleDesc pg_class_desc;
/*
* StartTransactionCommand and CommitTransactionCommand will automatically
*************** do_autovacuum(void)
*** 1890,1901 ****
shared = pgstat_fetch_stat_dbentry(InvalidOid);
classRel = heap_open(RelationRelationId, AccessShareLock);
! avRel = heap_open(AutovacuumRelationId, AccessShareLock);
/* create hash table for toast <-> main relid mapping */
MemSet(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(Oid);
! ctl.entrysize = sizeof(Oid) * 2;
ctl.hash = oid_hash;
table_toast_map = hash_create("TOAST to main relid map",
--- 1894,1907 ----
shared = pgstat_fetch_stat_dbentry(InvalidOid);
classRel = heap_open(RelationRelationId, 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(av_relation);
ctl.hash = oid_hash;
table_toast_map = hash_create("TOAST to main relid map",
*************** do_autovacuum(void)
*** 1909,1917 ****
* 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
--- 1915,1923 ----
* 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_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
*************** do_autovacuum(void)
*** 1931,1939 ****
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;
--- 1937,1944 ----
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
! AutoVacOpts *relopts;
Oid relid;
bool dovacuum;
bool doanalyze;
*************** do_autovacuum(void)
*** 1942,1958 ****
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 */
tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
shared, dbentry);
/* Check if it needs vacuum or analyze */
! relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/*
--- 1947,1959 ----
relid = HeapTupleGetOid(tuple);
! /* 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, relopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/*
*************** do_autovacuum(void)
*** 1998,2004 ****
}
else
{
! /* Plain relations that need work are added to table_oids */
if (dovacuum || doanalyze)
table_oids = lappend_oid(table_oids, relid);
--- 1999,2005 ----
}
else
{
! /* relations that need work are added to table_oids */
if (dovacuum || doanalyze)
table_oids = lappend_oid(table_oids, relid);
*************** do_autovacuum(void)
*** 2020,2031 ****
{
/* hash_search already filled in the key */
hentry->ar_relid = relid;
}
}
}
-
- if (HeapTupleIsValid(avTup))
- heap_freetuple(avTup);
}
heap_endscan(relScan);
--- 2021,2036 ----
{
/* 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));
+ }
}
}
}
}
heap_endscan(relScan);
*************** do_autovacuum(void)
*** 2040,2049 ****
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;
--- 2045,2053 ----
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
PgStat_StatTabEntry *tabentry;
Oid relid;
+ AutoVacOpts *relopts = NULL;
bool dovacuum;
bool doanalyze;
bool wraparound;
*************** do_autovacuum(void)
*** 2057,2073 ****
relid = HeapTupleGetOid(tuple);
! /* Fetch the pg_autovacuum tuple for this rel */
! 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 */
--- 2061,2086 ----
relid = HeapTupleGetOid(tuple);
! /*
! * 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;
! 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, relopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/* ignore analyze for toast tables */
*************** do_autovacuum(void)
*** 2076,2082 ****
}
heap_endscan(relScan);
- heap_close(avRel, AccessShareLock);
heap_close(classRel, AccessShareLock);
/*
--- 2089,2094 ----
*************** do_autovacuum(void)
*** 2163,2172 ****
* condition is not closed but it is very small.
*/
MemoryContextSwitchTo(AutovacMemCxt);
! tab = table_recheck_autovac(relid, table_toast_map);
if (tab == NULL)
{
! /* someone else vacuumed the table */
LWLockRelease(AutovacuumScheduleLock);
continue;
}
--- 2175,2184 ----
* condition is not closed but it is very small.
*/
MemoryContextSwitchTo(AutovacMemCxt);
! tab = table_recheck_autovac(relid, table_toast_map, pg_class_desc);
if (tab == NULL)
{
! /* someone else vacuumed the table, or it went away */
LWLockRelease(AutovacuumScheduleLock);
continue;
}
*************** deleted:
*** 2292,2340 ****
}
/*
! * 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.
*
! * 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
! get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
! HTAB *table_toast_map)
{
! ScanKeyData entry[1];
! SysScanDesc avScan;
! HeapTuple avTup;
! ScanKeyInit(&entry[0],
! Anum_pg_autovacuum_vacrelid,
! BTEqualStrategyNumber, F_OIDEQ,
! ObjectIdGetDatum(relid));
! 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);
! }
! return avTup;
}
/*
--- 2304,2332 ----
}
/*
! * extract_autovac_opts
*
! * Given a relation's pg_class tuple, return the AutoVacOpts portion of
! * reloptions, if set; otherwise, return NULL.
*/
! AutoVacOpts *
! extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
{
! bytea *relopts;
! AutoVacOpts *av;
! Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
! ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
! 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 av;
}
/*
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 2370,2382 ****
* 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)
{
- Form_pg_autovacuum avForm = NULL;
Form_pg_class classForm;
HeapTuple classTup;
- HeapTuple avTup;
- Relation avRel;
bool dovacuum;
bool doanalyze;
autovac_table *tab = NULL;
--- 2362,2372 ----
* 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,
! TupleDesc pg_class_desc)
{
Form_pg_class classForm;
HeapTuple classTup;
bool dovacuum;
bool doanalyze;
autovac_table *tab = NULL;
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2384,2389 ****
--- 2374,2380 ----
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
bool wraparound;
+ AutoVacOpts *avopts;
/* use fresh stats */
autovac_refresh_stats();
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2399,2421 ****
return NULL;
classForm = (Form_pg_class) GETSTRUCT(classTup);
! /*
! * Fetch the pg_autovacuum entry, if any. For a toast table, also try the
! * main rel's pg_autovacuum entry if there isn't one for the TOAST table
! * itself.
! */
! avRel = heap_open(AutovacuumRelationId, AccessShareLock);
! avTup = get_pg_autovacuum_tuple_relid(avRel, relid,
! classForm->relkind == RELKIND_TOASTVALUE ? table_toast_map : NULL);
! if (HeapTupleIsValid(avTup))
! avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
/* fetch the pgstat table entry */
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 */
--- 2390,2416 ----
return NULL;
classForm = (Form_pg_class) GETSTRUCT(classTup);
! /*
! * 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.
! */
! avopts = extract_autovac_opts(classTup, pg_class_desc);
! if (classForm->relkind == RELKIND_TOASTVALUE &&
! avopts == NULL && table_toast_map != NULL)
! {
! av_relation *hentry;
! bool found;
! 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, avopts, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
/* ignore ANALYZE for toast tables */
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2431,2471 ****
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.
! */
! if (avForm != NULL)
! {
! 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;
}
else
{
! vac_cost_limit = (autovacuum_vac_cost_limit > 0) ?
! autovacuum_vac_cost_limit : VacuumCostLimit;
!
! vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
autovacuum_vac_cost_delay : VacuumCostDelay;
!
freeze_min_age = default_freeze_min_age;
-
freeze_table_age = default_freeze_table_age;
}
--- 2426,2453 ----
int vac_cost_delay;
/*
! * 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 (avopts)
! {
! 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
{
! /* -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;
}
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2483,2491 ****
tab->at_datname = NULL;
}
- heap_close(avRel, AccessShareLock);
- if (HeapTupleIsValid(avTup))
- heap_freetuple(avTup);
heap_freetuple(classTup);
return tab;
--- 2465,2470 ----
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2496,2503 ****
*
* 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.
*
* A table needs to be vacuumed if the number of dead tuples exceeds a
* threshold. This threshold is calculated as
--- 2475,2486 ----
*
* 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.
! *
! * 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
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2513,2531 ****
* 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
* 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
* autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor
! * 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,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
/* output params below */
--- 2496,2514 ----
* We also force vacuum if the table's relfrozenxid is more than freeze_max_age
* transactions back.
*
! * 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
* autovacuum_vacuum_threshold GUC variable. Similarly, a vac_scale_factor
! * value < 0 is substituted with the value of
* autovacuum_vacuum_scale_factor GUC variable. Ditto for analyze.
*/
static void
relation_needs_vacanalyze(Oid relid,
! AutoVacOpts *relopts,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry,
/* output params below */
*************** relation_needs_vacanalyze(Oid relid,
*** 2534,2542 ****
bool *wraparound)
{
bool force_vacuum;
float4 reltuples; /* pg_class.reltuples */
! /* constants from pg_autovacuum or GUC variables */
int vac_base_thresh,
anl_base_thresh;
float4 vac_scale_factor,
--- 2517,2526 ----
bool *wraparound)
{
bool force_vacuum;
+ bool av_enabled;
float4 reltuples; /* pg_class.reltuples */
! /* constants from reloptions or GUC variables */
int vac_base_thresh,
anl_base_thresh;
float4 vac_scale_factor,
*************** relation_needs_vacanalyze(Oid relid,
*** 2554,2593 ****
int freeze_max_age;
TransactionId xidForceLimit;
- AssertArg(classForm != NULL);
- 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.
! */
! if (avForm != NULL)
! {
! 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;
}
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;
}
/* Force vacuum if table is at risk of wraparound */
--- 2538,2566 ----
int freeze_max_age;
TransactionId xidForceLimit;
/*
! * 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 (relopts)
! {
! 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 */
*************** relation_needs_vacanalyze(Oid relid,
*** 2599,2606 ****
xidForceLimit));
*wraparound = force_vacuum;
! /* User disabled it in pg_autovacuum? (But ignore if at risk) */
! if (avForm && !avForm->enabled && !force_vacuum)
{
*doanalyze = false;
*dovacuum = false;
--- 2572,2579 ----
xidForceLimit));
*wraparound = force_vacuum;
! /* User disabled it in pg_class.reloptions? (But ignore if at risk) */
! if (!force_vacuum && !av_enabled)
{
*doanalyze = false;
*dovacuum = false;
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/indexing.h,v
retrieving revision 1.106
diff -c -p -r1.106 indexing.h
*** src/include/catalog/indexing.h 22 Jan 2009 20:16:08 -0000 1.106
--- src/include/catalog/indexing.h 29 Jan 2009 17:23:12 -0000
*************** DECLARE_UNIQUE_INDEX(pg_auth_members_rol
*** 97,105 ****
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));
--- 97,102 ----
Index: src/include/utils/rel.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/utils/rel.h,v
retrieving revision 1.111
diff -c -p -r1.111 rel.h
*** src/include/utils/rel.h 1 Jan 2009 17:24:02 -0000 1.111
--- src/include/utils/rel.h 5 Feb 2009 21:23:07 -0000
*************** typedef struct RelationData
*** 214,223 ****
--- 214,239 ----
* 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
Index: src/test/regress/expected/sanity_check.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/sanity_check.out,v
retrieving revision 1.38
diff -c -p -r1.38 sanity_check.out
*** src/test/regress/expected/sanity_check.out 19 Dec 2008 16:25:19 -0000 1.38
--- src/test/regress/expected/sanity_check.out 29 Jan 2009 17:23:12 -0000
*************** SELECT relname, relhasindex
*** 90,96 ****
pg_attribute | t
pg_auth_members | t
pg_authid | t
- pg_autovacuum | t
pg_cast | t
pg_class | t
pg_constraint | t
--- 90,95 ----
*************** SELECT relname, relhasindex
*** 152,158 ****
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (141 rows)
--
-- another sanity check: every system catalog that has OIDs should have
--- 151,157 ----
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
! (140 rows)
--
-- another sanity check: every system catalog that has OIDs should have
Alvaro Herrera escreveu:
So here's what looks like a committable patch.
Note to self: remember to remove src/include/catalog/pg_autovacuum.h and
to bump catversion.
Works for me. Just a few comments.
(i) I don't like this construction "by entries by changing storage
parameters". I prefer "by changing storage parameters" or "by entries in
pg_class.reloptions";
(ii) I think we should change the expression "storage parameters" for
something else because autovacuum is related to maintenance. My suggestion is
a general expression like "relation parameters";
(iii) I noticed that GUC defaults and relopt defaults are different
(autovacuum_cost_delay and autovacuum_cost_limit). Is there any reason for not
using -1?
(iv) Maybe we should document that pg_dump will only dump reloptions like
toast.foo iff the relation has an associated TOAST table. This seems obvious
but ...
--
Euler Taveira de Oliveira
http://www.timbira.com/
Euler Taveira de Oliveira escribi�:
(i) I don't like this construction "by entries by changing storage
parameters". I prefer "by changing storage parameters" or "by entries in
pg_class.reloptions";
Heh, obvious "by entries by" is a cut'n'pasto; fixed.
Maybe an xref would be better there. I attach the doc patch again; I
fiddled a bit with it this morning. Comments?
(ii) I think we should change the expression "storage parameters" for
something else because autovacuum is related to maintenance. My suggestion is
a general expression like "relation parameters";
I'm not sure I agree with this idea, because the term "storage
parameter" has been used for several releases already. This would be a
relatively major terminology change.
(iii) I noticed that GUC defaults and relopt defaults are different
(autovacuum_cost_delay and autovacuum_cost_limit). Is there any reason for not
using -1?
Yeah, -1 does not make sense. It made sense in pg_autovacuum because
otherwise you didn't have to specify "skip this setting and use the
default". In reloptions, if you don't want to specify the setting, just
don't specify it.
(iv) Maybe we should document that pg_dump will only dump reloptions like
toast.foo iff the relation has an associated TOAST table. This seems obvious
but ...
Well, if it doesn't have a toast table, then there's no need for toast
settings, is there? I mean, you could construe it as a gotcha: if you
CREATE TABLE with only fixed-length columns and specify some reloptions,
and later add a column that requires a toast table, it won't have the
options you set at CREATE time. However, it seems to me to be very low
in the importance scale.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Attachments:
reloptions-autovacuum-docs.patchtext/x-diff; charset=us-asciiDownload
*** doc/src/sgml/catalogs.sgml 4 Feb 2009 21:30:41 -0000 2.194
--- doc/src/sgml/catalogs.sgml 5 Feb 2009 18:32:40 -0000
***************
*** 89,99 ****
</row>
<row>
- <entry><link linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</structname></link></entry>
- <entry>per-relation autovacuum configuration parameters</entry>
- </row>
-
- <row>
<entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
<entry>casts (data type conversions)</entry>
</row>
--- 89,94 ----
***************
*** 1256,1433 ****
</sect1>
- <sect1 id="catalog-pg-autovacuum">
- <title><structname>pg_autovacuum</structname></title>
-
- <indexterm zone="catalog-pg-autovacuum">
- <primary>pg_autovacuum</primary>
- </indexterm>
-
- <indexterm zone="catalog-pg-autovacuum">
- <primary>autovacuum</primary>
- <secondary>table-specific configuration</secondary>
- </indexterm>
-
- <para>
- The catalog <structname>pg_autovacuum</structname> stores optional
- per-relation configuration parameters for the autovacuum daemon.
- If there is an entry here for a particular relation, the given
- parameters will be used for autovacuuming that table. If no entry
- is present, the system-wide defaults will be used. For more information
- about the autovacuum daemon, see <xref linkend="autovacuum">.
- </para>
-
- <note>
- <para>
- It is likely that <structname>pg_autovacuum</structname> will disappear
- in a future release, with the information instead being kept in
- <structname>pg_class</>.<structfield>reloptions</> entries.
- </para>
- </note>
-
- <table>
- <title><structname>pg_autovacuum</> Columns</title>
-
- <tgroup cols="4">
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Type</entry>
- <entry>References</entry>
- <entry>Description</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry><structfield>vacrelid</structfield></entry>
- <entry><type>oid</type></entry>
- <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
- <entry>The table this entry is for</entry>
- </row>
-
- <row>
- <entry><structfield>enabled</structfield></entry>
- <entry><type>bool</type></entry>
- <entry></entry>
- <entry>If false, this table will not be autovacuumed, except
- to prevent transaction ID wraparound</entry>
- </row>
-
- <row>
- <entry><structfield>vac_base_thresh</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Minimum number of modified tuples before vacuum</entry>
- </row>
-
- <row>
- <entry><structfield>vac_scale_factor</structfield></entry>
- <entry><type>float4</type></entry>
- <entry></entry>
- <entry>Multiplier for <structfield>reltuples</> to add to
- <structfield>vac_base_thresh</></entry>
- </row>
-
- <row>
- <entry><structfield>anl_base_thresh</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Minimum number of modified tuples before analyze</entry>
- </row>
-
- <row>
- <entry><structfield>anl_scale_factor</structfield></entry>
- <entry><type>float4</type></entry>
- <entry></entry>
- <entry>Multiplier for <structfield>reltuples</> to add to
- <structfield>anl_base_thresh</></entry>
- </row>
-
- <row>
- <entry><structfield>vac_cost_delay</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_cost_delay</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>vac_cost_limit</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_cost_limit</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_min_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_freeze_min_age</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_max_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>autovacuum_freeze_max_age</> parameter</entry>
- </row>
-
- <row>
- <entry><structfield>freeze_table_age</structfield></entry>
- <entry><type>integer</type></entry>
- <entry></entry>
- <entry>Custom <varname>vacuum_freeze_table_age</> parameter</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- The autovacuum daemon will initiate a <command>VACUUM</> operation
- on a particular table when the number of updated or deleted tuples
- exceeds <structfield>vac_base_thresh</structfield> plus
- <structfield>vac_scale_factor</structfield> times the number of
- live tuples currently estimated to be in the relation.
- Similarly, it will initiate an <command>ANALYZE</> operation
- when the number of inserted, updated or deleted tuples
- exceeds <structfield>anl_base_thresh</structfield> plus
- <structfield>anl_scale_factor</structfield> times the number of
- live tuples currently estimated to be in the relation.
- </para>
-
- <para>
- Also, the autovacuum daemon will perform a <command>VACUUM</> operation
- to prevent transaction ID wraparound if the table's
- <structname>pg_class</>.<structfield>relfrozenxid</> field attains an age
- of more than <structfield>freeze_max_age</> transactions, whether the table
- has been changed or not, even if
- <structname>pg_autovacuum</>.<structfield>enabled</> is set to
- <literal>false</> for it. The system will launch autovacuum to perform
- such <command>VACUUM</>s even if autovacuum is otherwise disabled.
- See <xref linkend="vacuum-for-wraparound"> for more about wraparound
- prevention.
- </para>
-
- <para>
- Any of the numerical fields can contain <literal>-1</> (or indeed
- any negative value) to indicate that the system-wide default should
- be used for this particular value. Observe that the
- <structfield>vac_cost_delay</> variable inherits its default value from the
- <xref linkend="guc-autovacuum-vacuum-cost-delay"> configuration parameter,
- or from <xref linkend="guc-vacuum-cost-delay"> if the former is set to a
- negative value. The same applies to <structfield>vac_cost_limit</>.
- Also, autovacuum will ignore attempts to set a per-table
- <structfield>freeze_max_age</> larger than the system-wide setting (it can
- only be set smaller), and the <structfield>freeze_min_age</> value will be
- limited to half the system-wide <xref
- linkend="guc-autovacuum-freeze-max-age"> setting. Note that while you
- can set <structfield>freeze_max_age</> very small, or even zero, this
- is usually unwise since it will force frequent vacuuming.
- </para>
-
- </sect1>
-
-
<sect1 id="catalog-pg-cast">
<title><structname>pg_cast</structname></title>
--- 1251,1256 ----
*** doc/src/sgml/config.sgml 16 Jan 2009 13:27:23 -0000 1.206
--- doc/src/sgml/config.sgml 6 Feb 2009 17:27:58 -0000
***************
*** 3547,3554 ****
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3547,3554 ----
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
***************
*** 3565,3572 ****
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3565,3572 ----
The default is 50 tuples.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
***************
*** 3584,3591 ****
The default is 0.2 (20% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3584,3591 ----
The default is 0.2 (20% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
***************
*** 3603,3610 ****
The default is 0.1 (10% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3603,3610 ----
The default is 0.1 (10% of table size).
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
***************
*** 3624,3631 ****
autovacuum is otherwise disabled.
The default is 200 million transactions.
This parameter can only be set at server start, but the setting
! can be reduced for individual tables by entries in
! <structname>pg_autovacuum</>.
For more information see <xref linkend="vacuum-for-wraparound">.
</para>
</listitem>
--- 3624,3631 ----
autovacuum is otherwise disabled.
The default is 200 million transactions.
This parameter can only be set at server start, but the setting
! can be reduced for individual tables by
! changing storage parameters.
For more information see <xref linkend="vacuum-for-wraparound">.
</para>
</listitem>
***************
*** 3645,3652 ****
The default value is 20 milliseconds.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3645,3652 ----
The default value is 20 milliseconds.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
***************
*** 3667,3674 ****
each worker never exceeds the limit on this variable.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by entries in
! <structname>pg_autovacuum</>.
</para>
</listitem>
</varlistentry>
--- 3667,3674 ----
each worker never exceeds the limit on this variable.
This parameter can only be set in the <filename>postgresql.conf</>
file or on the server command line.
! This setting can be overridden for individual tables by
! changing storage parameters.
</para>
</listitem>
</varlistentry>
*** doc/src/sgml/maintenance.sgml 16 Jan 2009 13:27:23 -0000 1.89
--- doc/src/sgml/maintenance.sgml 6 Feb 2009 14:26:44 -0000
***************
*** 573,579 ****
<para>
Tables whose <structfield>relfrozenxid</> value is more than
<varname>autovacuum_freeze_max_age</> transactions old are always
! vacuumed. Otherwise, if the number of tuples obsoleted since the last
<command>VACUUM</command> exceeds the <quote>vacuum threshold</quote>, the
table is vacuumed. The vacuum threshold is defined as:
<programlisting>
--- 573,581 ----
<para>
Tables whose <structfield>relfrozenxid</> value is more than
<varname>autovacuum_freeze_max_age</> transactions old are always
! vacuumed (this also applies to those tables whose freeze max age has
! been modified via storage parameters; see below). Otherwise, if the
! number of tuples obsoleted since the last
<command>VACUUM</command> exceeds the <quote>vacuum threshold</quote>, the
table is vacuumed. The vacuum threshold is defined as:
<programlisting>
***************
*** 604,669 ****
<para>
The default thresholds and scale factors are taken from
<filename>postgresql.conf</filename>, but it is possible to override them
! on a table-by-table basis by making entries in the system catalog
! <link
! linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</></link>.
! If a <structname>pg_autovacuum</structname> row exists for a particular
! table, the settings it specifies are applied; otherwise the global
! settings are used. See <xref linkend="runtime-config-autovacuum"> for
more details on the global settings.
</para>
<para>
! Besides the base threshold values and scale factors, there are five
! more parameters that can be set for each table in
! <structname>pg_autovacuum</structname>.
! The first, <structname>pg_autovacuum</>.<structfield>enabled</>,
can be set to <literal>false</literal> to instruct the autovacuum daemon
to skip that particular table entirely. In this case
autovacuum will only touch the table if it must do so
to prevent transaction ID wraparound.
! The next two parameters, the vacuum cost delay
! (<structname>pg_autovacuum</structname>.<structfield>vac_cost_delay</structfield>)
! and the vacuum cost limit
! (<structname>pg_autovacuum</structname>.<structfield>vac_cost_limit</structfield>),
! are used to set table-specific values for the
! <xref linkend="runtime-config-resource-vacuum-cost" endterm="runtime-config-resource-vacuum-cost-title">
feature.
! The last two parameters,
! (<structname>pg_autovacuum</structname>.<structfield>freeze_min_age</structfield>)
! and
! (<structname>pg_autovacuum</structname>.<structfield>freeze_max_age</structfield>),
! are used to set table-specific values for
! <xref linkend="guc-vacuum-freeze-min-age"> and
! <xref linkend="guc-autovacuum-freeze-max-age"> respectively.
</para>
<para>
- If any of the values in <structname>pg_autovacuum</structname>
- are set to a negative number, or if a row is not present at all in
- <structname>pg_autovacuum</structname> for any particular table, the
- corresponding values from <filename>postgresql.conf</filename> are used.
- </para>
-
- <para>
- There is not currently any support for making
- <structname>pg_autovacuum</structname> entries, except by doing
- manual <command>INSERT</>s into the catalog. This feature will be
- improved in future releases, and it is likely that the catalog
- definition will change.
- </para>
-
- <caution>
- <para>
- The contents of the <structname>pg_autovacuum</structname> system
- catalog are currently not saved in database dumps created by the
- tools <application>pg_dump</> and <application>pg_dumpall</>. If
- you want to preserve them across a dump/reload cycle, make sure
- you dump the catalog manually.
- </para>
- </caution>
-
- <para>
When multiple workers are running, the cost limit is
<quote>balanced</quote> among all the running workers, so that the
total impact on the system is the same, regardless of the number
--- 606,645 ----
<para>
The default thresholds and scale factors are taken from
<filename>postgresql.conf</filename>, but it is possible to override them
! on a table-by-table basis; see
! <xref linkend="sql-createtable-storage-parameters"
! endterm="sql-createtable-storage-parameters-title"> for more information.
! If a setting
! has been changed via storage parameters, that value is used; otherwise the
! global settings are used. See <xref linkend="runtime-config-autovacuum"> for
more details on the global settings.
</para>
<para>
! Besides the base threshold values and scale factors, there are six
! more autovacuum parameters that can be set for each table via
! storage parameters.
! The first parameter, <literal>autovacuum_enabled</>,
can be set to <literal>false</literal> to instruct the autovacuum daemon
to skip that particular table entirely. In this case
autovacuum will only touch the table if it must do so
to prevent transaction ID wraparound.
! Another two parameters,
! <literal>autovacuum_vacuum_cost_delay</literal> and
! <literal>autovacuum_vacuum_cost_limit</literal>, are used to set
! table-specific values for the
! <xref linkend="runtime-config-resource-vacuum-cost"
! endterm="runtime-config-resource-vacuum-cost-title">
feature.
! <literal>autovacuum_freeze_min_age</literal>,
! <literal>autovacuum_freeze_max_age</literal> and
! <literal>autovacuum_freeze_table_age</literal> are used to set
! values for <xref linkend="guc-vacuum-freeze-min-age">,
! <xref linkend="guc-autovacuum-freeze-max-age"> and
! <xref linkend="guc-vacuum-freeze-table-age"> respectively.
</para>
<para>
When multiple workers are running, the cost limit is
<quote>balanced</quote> among all the running workers, so that the
total impact on the system is the same, regardless of the number
*** doc/src/sgml/ref/alter_index.sgml 14 Nov 2008 10:22:45 -0000 1.14
--- doc/src/sgml/ref/alter_index.sgml 29 Jan 2009 17:23:12 -0000
***************
*** 75,80 ****
--- 75,90 ----
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><replaceable class="PARAMETER">value</replaceable></term>
+ <listitem>
+ <para>
+ The new value for a storage parameter.
+ This might be a number or a word depending on the parameter.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] )</literal></term>
<listitem>
*** doc/src/sgml/ref/alter_table.sgml 13 Dec 2008 19:13:44 -0000 1.102
--- doc/src/sgml/ref/alter_table.sgml 6 Feb 2009 14:07:49 -0000
***************
*** 286,292 ****
<listitem>
<para>
This form changes one or more storage parameters for the table. See
! <xref linkend="SQL-CREATETABLE" endterm="sql-createtable-title">
for details on the available parameters. Note that the table contents
will not be modified immediately by this command; depending on the
parameter you might need to rewrite the table to get the desired effects.
--- 286,293 ----
<listitem>
<para>
This form changes one or more storage parameters for the table. See
! <xref linkend="SQL-CREATETABLE-storage-parameters"
! endterm="sql-createtable-storage-parameters-title">
for details on the available parameters. Note that the table contents
will not be modified immediately by this command; depending on the
parameter you might need to rewrite the table to get the desired effects.
*** doc/src/sgml/ref/create_table.sgml 2 Feb 2009 19:31:38 -0000 1.112
--- doc/src/sgml/ref/create_table.sgml 6 Feb 2009 14:20:05 -0000
***************
*** 685,703 ****
<refsect2 id="SQL-CREATETABLE-storage-parameters">
<title id="SQL-CREATETABLE-storage-parameters-title">Storage Parameters</title>
<para>
The <literal>WITH</> clause can specify <firstterm>storage parameters</>
for tables, and for indexes associated with a <literal>UNIQUE</literal> or
<literal>PRIMARY KEY</literal> constraint. Storage parameters for
indexes are documented in <xref linkend="SQL-CREATEINDEX"
endterm="sql-createindex-title">. The storage parameters currently
! available for tables are:
</para>
<variablelist>
<varlistentry>
! <term><literal>FILLFACTOR</></term>
<listitem>
<para>
The fillfactor for a table is a percentage between 10 and 100.
--- 685,713 ----
<refsect2 id="SQL-CREATETABLE-storage-parameters">
<title id="SQL-CREATETABLE-storage-parameters-title">Storage Parameters</title>
+ <indexterm zone="sql-createtable-storage-parameters">
+ <primary>storage parameters</primary>
+ </indexterm>
+
<para>
The <literal>WITH</> clause can specify <firstterm>storage parameters</>
for tables, and for indexes associated with a <literal>UNIQUE</literal> or
<literal>PRIMARY KEY</literal> constraint. Storage parameters for
indexes are documented in <xref linkend="SQL-CREATEINDEX"
endterm="sql-createindex-title">. The storage parameters currently
! available for tables are listed below. For each parameter, there is an
! additional, identically named parameter, prefixed with
! <literal>toast.</literal> which can be used to control the behavior of the
! supplementary storage table, if any; see <xref linkend="storage-toast">.
! Note that the supplementary storage table inherits the
! <literal>autovacuum</literal> values from its parent table, if there are
! no <literal>toast.autovacuum_*</literal> settings set.
</para>
<variablelist>
<varlistentry>
! <term><literal>fillfactor</>, <literal>toast.fillfactor</literal> (<type>integer</>)</term>
<listitem>
<para>
The fillfactor for a table is a percentage between 10 and 100.
***************
*** 715,725 ****
</varlistentry>
<varlistentry>
! <term><literal>TOAST.FILLFACTOR</literal></term>
<listitem>
<para>
! Same as above, for the supplementary storage table, if any; see
! <xref linkend="storage-toast">.
</para>
</listitem>
</varlistentry>
--- 725,842 ----
</varlistentry>
<varlistentry>
! <term><literal>autovacuum_enabled</>, <literal>toast.autovacuum_enabled</literal> (<type>boolean</>)</term>
! <listitem>
! <para>
! Enables or disables the autovacuum daemon on a particular table.
! If true, the autovacuum daemon will initiate a <command>VACUUM</> operation
! on a particular table when the number of updated or deleted tuples exceeds
! <literal>autovacuum_vacuum_threshold</> plus
! <literal>autovacuum_vacuum_scale_factor</> times the number of live tuples
! currently estimated to be in the relation.
! Similarly, it will initiate an <command>ANALYZE</> operation when the
! number of inserted, updated or deleted tuples exceeds
! <literal>autovacuum_analyze_threshold</> plus
! <literal>autovacuum_analyze_scale_factor</> times the number of live tuples
! currently estimated to be in the relation.
! If false, this table will not be autovacuumed, except to prevent
! transaction Id wraparound. See <xref linkend="vacuum-for-wraparound"> for
! more about wraparound prevention.
! Observe that this variable inherits its value from the <xref
! linkend="guc-autovacuum"> setting.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_vacuum_threshold</>, <literal>toast.autovacuum_vacuum_threshold</literal> (<type>integer</>)</term>
! <listitem>
! <para>
! Minimum number of updated or deleted tuples before initiate a
! <command>VACUUM</> operation on a particular table.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_vacuum_scale_factor</>, <literal>toast.autovacuum_vacuum_scale_factor</literal> (<type>float4</>)</term>
! <listitem>
! <para>
! Multiplier for <structfield>reltuples</> to add to
! <literal>autovacuum_vacuum_threshold</>.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_analyze_threshold</>, <literal>toast.autovacuum_analyze_threshold</literal> (<type>integer</>)</term>
! <listitem>
! <para>
! Minimum number of inserted, updated, or deleted tuples before initiate an
! <command>ANALYZE</> operation on a particular table.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_analyze_scale_factor</>, <literal>toast.autovacuum_analyze_scale_factor</literal> (<type>float4</>)</term>
! <listitem>
! <para>
! Multiplier for <structfield>reltuples</> to add to
! <literal>autovacuum_analyze_threshold</>.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_vacuum_cost_delay</>, <literal>toast.autovacuum_vacuum_cost_delay</literal> (<type>integer</>)</term>
! <listitem>
! <para>
! Custom <xref linkend="guc-autovacuum-vacuum-cost-delay"> parameter.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_vacuum_cost_limit</>, <literal>toast.autovacuum_vacuum_cost_limit</literal> (<type>integer</>)</term>
! <listitem>
! <para>
! Custom <xref linkend="guc-autovacuum-vacuum-cost-limit"> parameter.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_freeze_min_age</>, <literal>toast.autovacuum_freeze_min_age</literal> (<type>integer</>)</term>
! <listitem>
! <para>
! Custom <xref linkend="guc-vacuum-freeze-min-age"> parameter. Note that
! autovacuum will ignore attempts to set a per-table
! <literal>autovacuum_freeze_min_age</> larger than the half system-wide
! <xref linkend="guc-autovacuum-freeze-max-age"> setting.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_freeze_max_age</>, <literal>toast.autovacuum_freeze_max_age</literal> (<type>integer</>)</term>
! <listitem>
! <para>
! Custom <xref linkend="guc-autovacuum-freeze-max-age"> parameter. Note that
! autovacuum will ignore attempts to set a per-table
! <literal>autovacuum_freeze_max_age</> larger than the system-wide setting
! (it can only be set smaller). Note that while you can set
! <literal>autovacuum_freeze_max_age</> very small, or even zero, this is
! usually unwise since it will force frequent vacuuming.
! </para>
! </listitem>
! </varlistentry>
!
! <varlistentry>
! <term><literal>autovacuum_freeze_table_age</literal> (<type>integer</type>)</term>
<listitem>
<para>
! Custom <xref linkend="guc-vacuum-freeze-table-age"> parameter.
</para>
</listitem>
</varlistentry>
Alvaro Herrera escreveu:
(ii) I think we should change the expression "storage parameters" for
something else because autovacuum is related to maintenance. My suggestion is
a general expression like "relation parameters";I'm not sure I agree with this idea, because the term "storage
parameter" has been used for several releases already. This would be a
relatively major terminology change.
I don't buy your argument. 'fillfactor' is a _storage_ parameter but
'autovacuum_enabled' is not. I don't like terminology changes too but in this
case it sounds strange calling autovacuum_* as storage parameters.
--
Euler Taveira de Oliveira
http://www.timbira.com/
On Fri, Feb 6, 2009 at 5:45 PM, Euler Taveira de Oliveira
<euler@timbira.com> wrote:
Alvaro Herrera escreveu:
(ii) I think we should change the expression "storage parameters" for
something else because autovacuum is related to maintenance. My suggestion is
a general expression like "relation parameters";I'm not sure I agree with this idea, because the term "storage
parameter" has been used for several releases already. This would be a
relatively major terminology change.I don't buy your argument. 'fillfactor' is a _storage_ parameter but
'autovacuum_enabled' is not. I don't like terminology changes too but in this
case it sounds strange calling autovacuum_* as storage parameters.
+1
--
Atentamente,
Jaime Casanova
Soporte y capacitación de PostgreSQL
Asesoría y desarrollo de sistemas
Guayaquil - Ecuador
Cel. +59387171157