Commit 4ff695b1 authored by Alvaro Herrera's avatar Alvaro Herrera

Add log_min_autovacuum_duration per-table option

This is useful to control autovacuum log volume, for situations where
monitoring only a set of tables is necessary.

Author: Michael Paquier
Reviewed by: A team led by Naoya Anzai (also including Akira Kurosawa,
Taiki Kondo, Huong Dangminh), Fujii Masao.
parent a75fb9b3
...@@ -881,9 +881,9 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI ...@@ -881,9 +881,9 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
<literal>toast.</literal>, which can be used to control the behavior of the <literal>toast.</literal>, which can be used to control the behavior of the
table's secondary <acronym>TOAST</> table, if any table's secondary <acronym>TOAST</> table, if any
(see <xref linkend="storage-toast"> for more information about TOAST). (see <xref linkend="storage-toast"> for more information about TOAST).
Note that the TOAST table inherits the Note that the TOAST table uses the parameter values defined for
<literal>autovacuum_*</literal> values from its parent table, if there are the main table, for each parameter applicable to TOAST tables and
no <literal>toast.autovacuum_*</literal> settings set. for which no value is set in the TOAST table itself.
</para> </para>
<variablelist> <variablelist>
...@@ -1060,6 +1060,15 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI ...@@ -1060,6 +1060,15 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>log_autovacuum_min_duration</literal>, <literal>toast.log_autovacuum_min_duration</literal> (<type>integer</type>)</term>
<listitem>
<para>
Custom <xref linkend="guc-log-autovacuum-min-duration"> parameter.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><literal>user_catalog_table</literal> (<type>boolean</type>)</term> <term><literal>user_catalog_table</literal> (<type>boolean</type>)</term>
<listitem> <listitem>
...@@ -1067,6 +1076,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI ...@@ -1067,6 +1076,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
Declare a table as an additional catalog table, e.g. for the purpose of Declare a table as an additional catalog table, e.g. for the purpose of
logical replication. See logical replication. See
<xref linkend="logicaldecoding-capabilities"> for details. <xref linkend="logicaldecoding-capabilities"> for details.
This parameter cannot be set for TOAST tables.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -209,6 +209,14 @@ static relopt_int intRelOpts[] = ...@@ -209,6 +209,14 @@ static relopt_int intRelOpts[] =
RELOPT_KIND_HEAP | RELOPT_KIND_TOAST RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
}, -1, 0, 2000000000 }, -1, 0, 2000000000
}, },
{
{
"log_autovacuum_min_duration",
"Sets the minimum execution time above which autovacuum actions will be logged",
RELOPT_KIND_HEAP | RELOPT_KIND_TOAST
},
-1, -1, INT_MAX
},
{ {
{ {
"pages_per_range", "pages_per_range",
...@@ -1210,6 +1218,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) ...@@ -1210,6 +1218,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_max_age)}, offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_max_age)},
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT, {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_table_age)}, offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, multixact_freeze_table_age)},
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, log_min_duration)},
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL, {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_scale_factor)}, offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, vacuum_scale_factor)},
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
......
...@@ -85,7 +85,8 @@ static MemoryContext anl_context = NULL; ...@@ -85,7 +85,8 @@ static MemoryContext anl_context = NULL;
static BufferAccessStrategy vac_strategy; static BufferAccessStrategy vac_strategy;
static void do_analyze_rel(Relation onerel, int options, List *va_cols, static void do_analyze_rel(Relation onerel, int options,
VacuumParams *params, List *va_cols,
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
bool inh, bool in_outer_xact, int elevel); bool inh, bool in_outer_xact, int elevel);
static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks,
...@@ -115,8 +116,9 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull); ...@@ -115,8 +116,9 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
* analyze_rel() -- analyze one relation * analyze_rel() -- analyze one relation
*/ */
void void
analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols, analyze_rel(Oid relid, RangeVar *relation, int options,
bool in_outer_xact, BufferAccessStrategy bstrategy) VacuumParams *params, List *va_cols, bool in_outer_xact,
BufferAccessStrategy bstrategy)
{ {
Relation onerel; Relation onerel;
int elevel; int elevel;
...@@ -151,7 +153,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols, ...@@ -151,7 +153,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
else else
{ {
onerel = NULL; onerel = NULL;
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
ereport(LOG, ereport(LOG,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE), (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("skipping analyze of \"%s\" --- lock not available", errmsg("skipping analyze of \"%s\" --- lock not available",
...@@ -266,14 +268,14 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols, ...@@ -266,14 +268,14 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
/* /*
* Do the normal non-recursive ANALYZE. * Do the normal non-recursive ANALYZE.
*/ */
do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages, do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
false, in_outer_xact, elevel); false, in_outer_xact, elevel);
/* /*
* If there are child tables, do recursive ANALYZE. * If there are child tables, do recursive ANALYZE.
*/ */
if (onerel->rd_rel->relhassubclass) if (onerel->rd_rel->relhassubclass)
do_analyze_rel(onerel, options, va_cols, acquirefunc, relpages, do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
true, in_outer_xact, elevel); true, in_outer_xact, elevel);
/* /*
...@@ -301,9 +303,10 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols, ...@@ -301,9 +303,10 @@ analyze_rel(Oid relid, RangeVar *relation, int options, List *va_cols,
* appropriate acquirefunc for each child table. * appropriate acquirefunc for each child table.
*/ */
static void static void
do_analyze_rel(Relation onerel, int options, List *va_cols, do_analyze_rel(Relation onerel, int options, VacuumParams *params,
AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, List *va_cols, AcquireSampleRowsFunc acquirefunc,
bool inh, bool in_outer_xact, int elevel) BlockNumber relpages, bool inh, bool in_outer_xact,
int elevel)
{ {
int attr_cnt, int attr_cnt,
tcnt, tcnt,
...@@ -359,10 +362,10 @@ do_analyze_rel(Relation onerel, int options, List *va_cols, ...@@ -359,10 +362,10 @@ do_analyze_rel(Relation onerel, int options, List *va_cols,
save_nestlevel = NewGUCNestLevel(); save_nestlevel = NewGUCNestLevel();
/* measure elapsed time iff autovacuum logging requires it */ /* measure elapsed time iff autovacuum logging requires it */
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
{ {
pg_rusage_init(&ru0); pg_rusage_init(&ru0);
if (Log_autovacuum_min_duration > 0) if (params->log_min_duration > 0)
starttime = GetCurrentTimestamp(); starttime = GetCurrentTimestamp();
} }
...@@ -647,11 +650,11 @@ do_analyze_rel(Relation onerel, int options, List *va_cols, ...@@ -647,11 +650,11 @@ do_analyze_rel(Relation onerel, int options, List *va_cols,
vac_close_indexes(nindexes, Irel, NoLock); vac_close_indexes(nindexes, Irel, NoLock);
/* Log the action if appropriate */ /* Log the action if appropriate */
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
{ {
if (Log_autovacuum_min_duration == 0 || if (params->log_min_duration == 0 ||
TimestampDifferenceExceeds(starttime, GetCurrentTimestamp(), TimestampDifferenceExceeds(starttime, GetCurrentTimestamp(),
Log_autovacuum_min_duration)) params->log_min_duration))
ereport(LOG, ereport(LOG,
(errmsg("automatic analyze of table \"%s.%s.%s\" system usage: %s", (errmsg("automatic analyze of table \"%s.%s.%s\" system usage: %s",
get_database_name(MyDatabaseId), get_database_name(MyDatabaseId),
......
...@@ -114,6 +114,9 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel) ...@@ -114,6 +114,9 @@ ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel)
/* user-invoked vacuum is never "for wraparound" */ /* user-invoked vacuum is never "for wraparound" */
params.is_wraparound = false; params.is_wraparound = false;
/* user-invoked vacuum never uses this parameter */
params.log_min_duration = -1;
/* Now go through the common routine */ /* Now go through the common routine */
vacuum(vacstmt->options, vacstmt->relation, InvalidOid, &params, vacuum(vacstmt->options, vacstmt->relation, InvalidOid, &params,
vacstmt->va_cols, NULL, isTopLevel); vacstmt->va_cols, NULL, isTopLevel);
...@@ -304,7 +307,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, ...@@ -304,7 +307,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
PushActiveSnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
} }
analyze_rel(relid, relation, options, analyze_rel(relid, relation, options, params,
va_cols, in_outer_xact, vac_strategy); va_cols, in_outer_xact, vac_strategy);
if (use_own_xacts) if (use_own_xacts)
...@@ -1233,7 +1236,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) ...@@ -1233,7 +1236,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
else else
{ {
onerel = NULL; onerel = NULL;
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
ereport(LOG, ereport(LOG,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE), (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("skipping vacuum of \"%s\" --- lock not available", errmsg("skipping vacuum of \"%s\" --- lock not available",
......
...@@ -196,7 +196,7 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, ...@@ -196,7 +196,7 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
Assert(params != NULL); Assert(params != NULL);
/* measure elapsed time iff autovacuum logging requires it */ /* measure elapsed time iff autovacuum logging requires it */
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
{ {
pg_rusage_init(&ru0); pg_rusage_init(&ru0);
starttime = GetCurrentTimestamp(); starttime = GetCurrentTimestamp();
...@@ -328,13 +328,13 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, ...@@ -328,13 +328,13 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params,
vacrelstats->new_dead_tuples); vacrelstats->new_dead_tuples);
/* and log the action if appropriate */ /* and log the action if appropriate */
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
{ {
TimestampTz endtime = GetCurrentTimestamp(); TimestampTz endtime = GetCurrentTimestamp();
if (Log_autovacuum_min_duration == 0 || if (params->log_min_duration == 0 ||
TimestampDifferenceExceeds(starttime, endtime, TimestampDifferenceExceeds(starttime, endtime,
Log_autovacuum_min_duration)) params->log_min_duration))
{ {
StringInfoData buf; StringInfoData buf;
TimestampDifference(starttime, endtime, &secs, &usecs); TimestampDifference(starttime, endtime, &secs, &usecs);
......
...@@ -2493,6 +2493,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, ...@@ -2493,6 +2493,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_table_age; int multixact_freeze_table_age;
int vac_cost_limit; int vac_cost_limit;
int vac_cost_delay; int vac_cost_delay;
int log_min_duration;
/* /*
* Calculate the vacuum cost parameters and the freeze ages. If there * Calculate the vacuum cost parameters and the freeze ages. If there
...@@ -2515,6 +2516,11 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, ...@@ -2515,6 +2516,11 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
? autovacuum_vac_cost_limit ? autovacuum_vac_cost_limit
: VacuumCostLimit; : VacuumCostLimit;
/* -1 in autovac setting means use log_autovacuum_min_duration */
log_min_duration = (avopts && avopts->log_min_duration >= 0)
? avopts->log_min_duration
: Log_autovacuum_min_duration;
/* these do not have autovacuum-specific settings */ /* these do not have autovacuum-specific settings */
freeze_min_age = (avopts && avopts->freeze_min_age >= 0) freeze_min_age = (avopts && avopts->freeze_min_age >= 0)
? avopts->freeze_min_age ? avopts->freeze_min_age
...@@ -2545,6 +2551,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, ...@@ -2545,6 +2551,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age; tab->at_params.multixact_freeze_min_age = multixact_freeze_min_age;
tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age; tab->at_params.multixact_freeze_table_age = multixact_freeze_table_age;
tab->at_params.is_wraparound = wraparound; tab->at_params.is_wraparound = wraparound;
tab->at_params.log_min_duration = log_min_duration;
tab->at_vacuum_cost_limit = vac_cost_limit; tab->at_vacuum_cost_limit = vac_cost_limit;
tab->at_vacuum_cost_delay = vac_cost_delay; tab->at_vacuum_cost_delay = vac_cost_delay;
tab->at_relname = NULL; tab->at_relname = NULL;
......
...@@ -1788,6 +1788,7 @@ psql_completion(const char *text, int start, int end) ...@@ -1788,6 +1788,7 @@ psql_completion(const char *text, int start, int end)
"autovacuum_vacuum_scale_factor", "autovacuum_vacuum_scale_factor",
"autovacuum_vacuum_threshold", "autovacuum_vacuum_threshold",
"fillfactor", "fillfactor",
"log_autovacuum_min_duration",
"toast.autovacuum_enabled", "toast.autovacuum_enabled",
"toast.autovacuum_freeze_max_age", "toast.autovacuum_freeze_max_age",
"toast.autovacuum_freeze_min_age", "toast.autovacuum_freeze_min_age",
...@@ -1799,6 +1800,7 @@ psql_completion(const char *text, int start, int end) ...@@ -1799,6 +1800,7 @@ psql_completion(const char *text, int start, int end)
"toast.autovacuum_vacuum_cost_limit", "toast.autovacuum_vacuum_cost_limit",
"toast.autovacuum_vacuum_scale_factor", "toast.autovacuum_vacuum_scale_factor",
"toast.autovacuum_vacuum_threshold", "toast.autovacuum_vacuum_threshold",
"toast.log_autovacuum_min_duration",
"user_catalog_table", "user_catalog_table",
NULL NULL
}; };
......
...@@ -142,6 +142,9 @@ typedef struct VacuumParams ...@@ -142,6 +142,9 @@ typedef struct VacuumParams
int multixact_freeze_table_age; /* multixact age at which to int multixact_freeze_table_age; /* multixact age at which to
* scan whole table */ * scan whole table */
bool is_wraparound; /* force a for-wraparound vacuum */ bool is_wraparound; /* force a for-wraparound vacuum */
int log_min_duration; /* minimum execution threshold in ms at
* which verbose logs are activated,
* -1 to use default */
} VacuumParams; } VacuumParams;
/* GUC parameters */ /* GUC parameters */
...@@ -191,7 +194,7 @@ extern void lazy_vacuum_rel(Relation onerel, int options, ...@@ -191,7 +194,7 @@ extern void lazy_vacuum_rel(Relation onerel, int options,
/* in commands/analyze.c */ /* in commands/analyze.c */
extern void analyze_rel(Oid relid, RangeVar *relation, int options, extern void analyze_rel(Oid relid, RangeVar *relation, int options,
List *va_cols, bool in_outer_xact, VacuumParams *params, List *va_cols, bool in_outer_xact,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);
extern bool std_typanalyze(VacAttrStats *stats); extern bool std_typanalyze(VacAttrStats *stats);
extern double anl_random_fract(void); extern double anl_random_fract(void);
......
...@@ -209,6 +209,7 @@ typedef struct AutoVacOpts ...@@ -209,6 +209,7 @@ typedef struct AutoVacOpts
int multixact_freeze_min_age; int multixact_freeze_min_age;
int multixact_freeze_max_age; int multixact_freeze_max_age;
int multixact_freeze_table_age; int multixact_freeze_table_age;
int log_min_duration;
float8 vacuum_scale_factor; float8 vacuum_scale_factor;
float8 analyze_scale_factor; float8 analyze_scale_factor;
} AutoVacOpts; } AutoVacOpts;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment