Commit caf626b2 authored by Tom Lane's avatar Tom Lane

Convert [autovacuum_]vacuum_cost_delay into floating-point GUCs.

This change makes it possible to specify sub-millisecond delays,
which work well on most modern platforms, though that was not true
when the cost-delay feature was designed.

To support this without breaking existing configuration entries,
improve guc.c to allow floating-point GUCs to have units.  Also,
allow "us" (microseconds) as an input/output unit for time-unit GUCs.
(It's not allowed as a base unit, at least not yet.)

Likewise change the autovacuum_vacuum_cost_delay reloption to be
floating-point; this forces a catversion bump because the layout of
StdRdOptions changes.

This patch doesn't in itself change the default values or allowed
ranges for these parameters, and it should not affect the behavior
for any already-allowed setting for them.

Discussion: https://postgr.es/m/1798.1552165479@sss.pgh.pa.us
parent 28a65fc3
......@@ -91,7 +91,9 @@
<listitem>
<para>
Valid time units are <literal>ms</literal> (milliseconds),
Valid time units are
<literal>us</literal> (microseconds),
<literal>ms</literal> (milliseconds),
<literal>s</literal> (seconds), <literal>min</literal> (minutes),
<literal>h</literal> (hours), and <literal>d</literal> (days).
</para>
......@@ -1845,7 +1847,7 @@ include_dir 'conf.d'
<variablelist>
<varlistentry id="guc-vacuum-cost-delay" xreflabel="vacuum_cost_delay">
<term><varname>vacuum_cost_delay</varname> (<type>integer</type>)
<term><varname>vacuum_cost_delay</varname> (<type>floating point</type>)
<indexterm>
<primary><varname>vacuum_cost_delay</varname> configuration parameter</primary>
</indexterm>
......@@ -1856,18 +1858,19 @@ include_dir 'conf.d'
when the cost limit has been exceeded.
The default value is zero, which disables the cost-based vacuum
delay feature. Positive values enable cost-based vacuuming.
Note that on many systems, the effective resolution
of sleep delays is 10 milliseconds; setting
<varname>vacuum_cost_delay</varname> to a value that is
not a multiple of 10 might have the same results as setting it
to the next higher multiple of 10.
</para>
<para>
When using cost-based vacuuming, appropriate values for
<varname>vacuum_cost_delay</varname> are usually quite small, perhaps
10 or 20 milliseconds. Adjusting vacuum's resource consumption
is best done by changing the other vacuum cost parameters.
less than 1 millisecond. While <varname>vacuum_cost_delay</varname>
can be set to fractional-millisecond values, such delays may not be
measured accurately on older platforms. On such platforms,
increasing <command>VACUUM</command>'s throttled resource consumption
above what you get at 1ms will require changing the other vacuum cost
parameters. You should, nonetheless,
keep <varname>vacuum_cost_delay</varname> as small as your platform
will consistently measure; large delays are not helpful.
</para>
</listitem>
</varlistentry>
......@@ -7020,7 +7023,7 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
</varlistentry>
<varlistentry id="guc-autovacuum-vacuum-cost-delay" xreflabel="autovacuum_vacuum_cost_delay">
<term><varname>autovacuum_vacuum_cost_delay</varname> (<type>integer</type>)
<term><varname>autovacuum_vacuum_cost_delay</varname> (<type>floating point</type>)
<indexterm>
<primary><varname>autovacuum_vacuum_cost_delay</varname> configuration parameter</primary>
</indexterm>
......
......@@ -1385,7 +1385,7 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
</varlistentry>
<varlistentry>
<term><literal>autovacuum_vacuum_cost_delay</literal>, <literal>toast.autovacuum_vacuum_cost_delay</literal> (<type>integer</type>)</term>
<term><literal>autovacuum_vacuum_cost_delay</literal>, <literal>toast.autovacuum_vacuum_cost_delay</literal> (<type>floating point</type>)</term>
<listitem>
<para>
Per-table value for <xref linkend="guc-autovacuum-vacuum-cost-delay"/>
......
......@@ -1198,7 +1198,7 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
{
relopt_real *optreal = (relopt_real *) option->gen;
parsed = parse_real(value, &option->values.real_val);
parsed = parse_real(value, &option->values.real_val, 0, NULL);
if (validate && !parsed)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
......@@ -1359,8 +1359,6 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
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,
......@@ -1379,6 +1377,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
{"toast_tuple_target", RELOPT_TYPE_INT,
offsetof(StdRdOptions, toast_tuple_target)},
{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
......
......@@ -1834,13 +1834,13 @@ vacuum_delay_point(void)
if (VacuumCostActive && !InterruptPending &&
VacuumCostBalance >= VacuumCostLimit)
{
int msec;
double msec;
msec = VacuumCostDelay * VacuumCostBalance / VacuumCostLimit;
if (msec > VacuumCostDelay * 4)
msec = VacuumCostDelay * 4;
pg_usleep(msec * 1000L);
pg_usleep((long) (msec * 1000));
VacuumCostBalance = 0;
......
......@@ -120,7 +120,7 @@ double autovacuum_anl_scale;
int autovacuum_freeze_max_age;
int autovacuum_multixact_freeze_max_age;
int autovacuum_vac_cost_delay;
double autovacuum_vac_cost_delay;
int autovacuum_vac_cost_limit;
int Log_autovacuum_min_duration = -1;
......@@ -189,7 +189,7 @@ typedef struct autovac_table
Oid at_relid;
int at_vacoptions; /* bitmask of VacuumOption */
VacuumParams at_params;
int at_vacuum_cost_delay;
double at_vacuum_cost_delay;
int at_vacuum_cost_limit;
bool at_dobalance;
bool at_sharedrel;
......@@ -225,7 +225,7 @@ typedef struct WorkerInfoData
TimestampTz wi_launchtime;
bool wi_dobalance;
bool wi_sharedrel;
int wi_cost_delay;
double wi_cost_delay;
int wi_cost_limit;
int wi_cost_limit_base;
} WorkerInfoData;
......@@ -1785,7 +1785,7 @@ autovac_balance_cost(void)
*/
int vac_cost_limit = (autovacuum_vac_cost_limit > 0 ?
autovacuum_vac_cost_limit : VacuumCostLimit);
int vac_cost_delay = (autovacuum_vac_cost_delay >= 0 ?
double vac_cost_delay = (autovacuum_vac_cost_delay >= 0 ?
autovacuum_vac_cost_delay : VacuumCostDelay);
double cost_total;
double cost_avail;
......@@ -1840,7 +1840,7 @@ autovac_balance_cost(void)
}
if (worker->wi_proc != NULL)
elog(DEBUG2, "autovac_balance_cost(pid=%u db=%u, rel=%u, dobalance=%s cost_limit=%d, cost_limit_base=%d, cost_delay=%d)",
elog(DEBUG2, "autovac_balance_cost(pid=%u db=%u, rel=%u, dobalance=%s cost_limit=%d, cost_limit_base=%d, cost_delay=%g)",
worker->wi_proc->pid, worker->wi_dboid, worker->wi_tableoid,
worker->wi_dobalance ? "yes" : "no",
worker->wi_cost_limit, worker->wi_cost_limit_base,
......@@ -2302,7 +2302,7 @@ do_autovacuum(void)
autovac_table *tab;
bool isshared;
bool skipit;
int stdVacuumCostDelay;
double stdVacuumCostDelay;
int stdVacuumCostLimit;
dlist_iter iter;
......@@ -2831,7 +2831,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
int multixact_freeze_min_age;
int multixact_freeze_table_age;
int vac_cost_limit;
int vac_cost_delay;
double vac_cost_delay;
int log_min_duration;
/*
......@@ -2993,7 +2993,7 @@ relation_needs_vacanalyze(Oid relid,
* table), or the autovacuum GUC variables.
*/
/* -1 in autovac setting means use plain vacuum_cost_delay */
/* -1 in autovac setting means use plain vacuum_scale_factor */
vac_scale_factor = (relopts && relopts->vacuum_scale_factor >= 0)
? relopts->vacuum_scale_factor
: autovacuum_vac_scale;
......
......@@ -138,7 +138,7 @@ int VacuumCostPageHit = 1; /* GUC parameters for vacuum */
int VacuumCostPageMiss = 10;
int VacuumCostPageDirty = 20;
int VacuumCostLimit = 2000;
int VacuumCostDelay = 0;
double VacuumCostDelay = 0;
int VacuumPageHit = 0;
int VacuumPageMiss = 0;
......
This diff is collapsed.
......@@ -155,7 +155,7 @@
# - Cost-Based Vacuum Delay -
#vacuum_cost_delay = 0 # 0-100 milliseconds
#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables)
#vacuum_cost_page_hit = 1 # 0-10000 credits
#vacuum_cost_page_miss = 10 # 0-10000 credits
#vacuum_cost_page_dirty = 20 # 0-10000 credits
......
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201903091
#define CATALOG_VERSION_NO 201903101
#endif
......@@ -250,7 +250,7 @@ extern int VacuumCostPageHit;
extern int VacuumCostPageMiss;
extern int VacuumCostPageDirty;
extern int VacuumCostLimit;
extern int VacuumCostDelay;
extern double VacuumCostDelay;
extern int VacuumPageHit;
extern int VacuumPageMiss;
......
......@@ -37,7 +37,7 @@ extern int autovacuum_anl_thresh;
extern double autovacuum_anl_scale;
extern int autovacuum_freeze_max_age;
extern int autovacuum_multixact_freeze_max_age;
extern int autovacuum_vac_cost_delay;
extern double autovacuum_vac_cost_delay;
extern int autovacuum_vac_cost_limit;
/* autovacuum launcher PID, only valid when worker is shutting down */
......
......@@ -361,7 +361,8 @@ extern void BeginReportingGUCOptions(void);
extern void ParseLongOption(const char *string, char **name, char **value);
extern bool parse_int(const char *value, int *result, int flags,
const char **hintmsg);
extern bool parse_real(const char *value, double *result);
extern bool parse_real(const char *value, double *result, int flags,
const char **hintmsg);
extern int set_config_option(const char *name, const char *value,
GucContext context, GucSource source,
GucAction action, bool changeVal, int elevel,
......
......@@ -243,7 +243,6 @@ 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;
......@@ -252,6 +251,7 @@ typedef struct AutoVacOpts
int multixact_freeze_max_age;
int multixact_freeze_table_age;
int log_min_duration;
float8 vacuum_cost_delay;
float8 vacuum_scale_factor;
float8 analyze_scale_factor;
} AutoVacOpts;
......
......@@ -149,11 +149,11 @@ SELECT '2006-08-13 12:34:56'::timestamptz;
(1 row)
SAVEPOINT first_sp;
SET vacuum_cost_delay TO 80;
SET vacuum_cost_delay TO 80.1;
SHOW vacuum_cost_delay;
vacuum_cost_delay
-------------------
80ms
80100us
(1 row)
SET datestyle = 'German, DMY';
......@@ -183,7 +183,7 @@ SELECT '2006-08-13 12:34:56'::timestamptz;
(1 row)
SAVEPOINT second_sp;
SET vacuum_cost_delay TO 90;
SET vacuum_cost_delay TO '900us';
SET datestyle = 'SQL, YMD';
SHOW datestyle;
DateStyle
......@@ -222,7 +222,7 @@ ROLLBACK TO third_sp;
SHOW vacuum_cost_delay;
vacuum_cost_delay
-------------------
90ms
900us
(1 row)
SHOW datestyle;
......@@ -508,7 +508,7 @@ SELECT '2006-08-13 12:34:56'::timestamptz;
-- Test some simple error cases
SET seq_page_cost TO 'NaN';
ERROR: parameter "seq_page_cost" requires a numeric value
ERROR: invalid value for parameter "seq_page_cost": "NaN"
SET vacuum_cost_delay TO '10s';
ERROR: 10000 ms is outside the valid range for parameter "vacuum_cost_delay" (0 .. 100)
SET geqo_selection_bias TO '-infinity';
......
......@@ -47,7 +47,7 @@ SET datestyle = 'MDY';
SHOW datestyle;
SELECT '2006-08-13 12:34:56'::timestamptz;
SAVEPOINT first_sp;
SET vacuum_cost_delay TO 80;
SET vacuum_cost_delay TO 80.1;
SHOW vacuum_cost_delay;
SET datestyle = 'German, DMY';
SHOW datestyle;
......@@ -56,7 +56,7 @@ ROLLBACK TO first_sp;
SHOW datestyle;
SELECT '2006-08-13 12:34:56'::timestamptz;
SAVEPOINT second_sp;
SET vacuum_cost_delay TO 90;
SET vacuum_cost_delay TO '900us';
SET datestyle = 'SQL, YMD';
SHOW datestyle;
SELECT '2006-08-13 12:34:56'::timestamptz;
......
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