Introduce a maintenance_io_concurrency setting.

Introduce a GUC and a tablespace option to control I/O prefetching, much
like effective_io_concurrency, but for work that is done on behalf of
many client sessions.

Use the new setting in heapam.c instead of the hard-coded formula
effective_io_concurrency + 10 introduced by commit 558a9165e0.  Go with
a default value of 10 for now, because it's a round number pretty close
to the value used for that existing case.

Discussion: https://postgr.es/m/CA%2BhUKGJUw08dPs_3EUcdO6M90GnjofPYrWp4YSLaBkgYwS-AqA%40mail.gmail.com
This commit is contained in:
Thomas Munro 2020-03-16 12:31:34 +13:00
parent b09ff53667
commit fc34b0d9de
12 changed files with 109 additions and 23 deletions

View File

@ -2229,6 +2229,26 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
<varlistentry id="guc-maintenance-io-concurrency" xreflabel="maintenance_io_concurrency">
<term><varname>maintenance_io_concurrency</varname> (<type>integer</type>)
<indexterm>
<primary><varname>maintenance_io_concurrency</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Similar to <varname>effective_io_concurrency</varname>, but used
for maintenance work that is done on behalf of many client sessions.
</para>
<para>
The default is 10 on supported systems, otherwise 0. This value can
be overridden for tables in a particular tablespace by setting the
tablespace parameter of the same name (see
<xref linkend="sql-altertablespace"/>).
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-max-worker-processes" xreflabel="max_worker_processes">
<term><varname>max_worker_processes</varname> (<type>integer</type>)
<indexterm>

View File

@ -84,13 +84,16 @@ ALTER TABLESPACE <replaceable>name</replaceable> RESET ( <replaceable class="par
<para>
A tablespace parameter to be set or reset. Currently, the only
available parameters are <varname>seq_page_cost</varname>,
<varname>random_page_cost</varname> and <varname>effective_io_concurrency</varname>.
Setting either value for a particular tablespace will override the
<varname>random_page_cost</varname>, <varname>effective_io_concurrency</varname>
and <varname>maintenance_io_concurrency</varname>.
Setting these values for a particular tablespace will override the
planner's usual estimate of the cost of reading pages from tables in
that tablespace, as established by the configuration parameters of the
that tablespace, and the executor's prefetching behavior, as established
by the configuration parameters of the
same name (see <xref linkend="guc-seq-page-cost"/>,
<xref linkend="guc-random-page-cost"/>,
<xref linkend="guc-effective-io-concurrency"/>). This may be useful if
<xref linkend="guc-effective-io-concurrency"/>,
<xref linkend="guc-maintenance-io-concurrency"/>). This may be useful if
one tablespace is located on a disk which is faster or slower than the
remainder of the I/O subsystem.
</para>

View File

@ -106,13 +106,16 @@ CREATE TABLESPACE <replaceable class="parameter">tablespace_name</replaceable>
<para>
A tablespace parameter to be set or reset. Currently, the only
available parameters are <varname>seq_page_cost</varname>,
<varname>random_page_cost</varname> and <varname>effective_io_concurrency</varname>.
Setting either value for a particular tablespace will override the
<varname>random_page_cost</varname>, <varname>effective_io_concurrency</varname>
and <varname>maintenance_io_concurrency</varname>.
Setting these values for a particular tablespace will override the
planner's usual estimate of the cost of reading pages from tables in
that tablespace, as established by the configuration parameters of the
that tablespace, and the executor's prefetching behavior, as established
by the configuration parameters of the
same name (see <xref linkend="guc-seq-page-cost"/>,
<xref linkend="guc-random-page-cost"/>,
<xref linkend="guc-effective-io-concurrency"/>). This may be useful if
<xref linkend="guc-effective-io-concurrency"/>,
<xref linkend="guc-maintenance-io-concurrency"/>). This may be useful if
one tablespace is located on a disk which is faster or slower than the
remainder of the I/O subsystem.
</para>

View File

@ -349,6 +349,19 @@ static relopt_int intRelOpts[] =
-1, 0, MAX_IO_CONCURRENCY
#else
0, 0, 0
#endif
},
{
{
"maintenance_io_concurrency",
"Number of simultaneous requests that can be handled efficiently by the disk subsystem for maintenance work.",
RELOPT_KIND_TABLESPACE,
ShareUpdateExclusiveLock
},
#ifdef USE_PREFETCH
-1, 0, MAX_IO_CONCURRENCY
#else
0, 0, 0
#endif
},
{
@ -1700,7 +1713,8 @@ tablespace_reloptions(Datum reloptions, bool validate)
static const relopt_parse_elt tab[] = {
{"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
{"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)},
{"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)}
{"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)},
{"maintenance_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, maintenance_io_concurrency)}
};
return (bytea *) build_reloptions(reloptions, validate,

View File

@ -7003,7 +7003,6 @@ heap_compute_xid_horizon_for_tuples(Relation rel,
Page hpage;
#ifdef USE_PREFETCH
XidHorizonPrefetchState prefetch_state;
int io_concurrency;
int prefetch_distance;
#endif
@ -7026,24 +7025,15 @@ heap_compute_xid_horizon_for_tuples(Relation rel,
/*
* Compute the prefetch distance that we will attempt to maintain.
*
* We don't use the regular formula to determine how much to prefetch
* here, but instead just add a constant to effective_io_concurrency.
* That's because it seems best to do some prefetching here even when
* effective_io_concurrency is set to 0, but if the DBA thinks it's OK to
* do more prefetching for other operations, then it's probably OK to do
* more prefetching in this case, too. It may be that this formula is too
* simplistic, but at the moment there is no evidence of that or any idea
* about what would work better.
*
* Since the caller holds a buffer lock somewhere in rel, we'd better make
* sure that isn't a catalog relation before we call code that does
* syscache lookups, to avoid risk of deadlock.
*/
if (IsCatalogRelation(rel))
io_concurrency = effective_io_concurrency;
prefetch_distance = maintenance_io_concurrency;
else
io_concurrency = get_tablespace_io_concurrency(rel->rd_rel->reltablespace);
prefetch_distance = Min((io_concurrency) + 10, MAX_IO_CONCURRENCY);
prefetch_distance =
get_tablespace_maintenance_io_concurrency(rel->rd_rel->reltablespace);
/* Start prefetching. */
xid_horizon_prefetch_buffer(rel, &prefetch_state, prefetch_distance);

View File

@ -119,6 +119,13 @@ bool track_io_timing = false;
*/
int effective_io_concurrency = 0;
/*
* Like effective_io_concurrency, but used by maintenance code paths that might
* benefit from a higher setting because they work on behalf of many sessions.
* Overridden by the tablespace setting of the same name.
*/
int maintenance_io_concurrency = 0;
/*
* GUC variables about triggering kernel writeback for buffers written; OS
* dependent defaults are set via the GUC mechanism.

View File

@ -221,3 +221,17 @@ get_tablespace_io_concurrency(Oid spcid)
else
return spc->opts->effective_io_concurrency;
}
/*
* get_tablespace_maintenance_io_concurrency
*/
int
get_tablespace_maintenance_io_concurrency(Oid spcid)
{
TableSpaceCacheEntry *spc = get_tablespace(spcid);
if (!spc->opts || spc->opts->maintenance_io_concurrency < 0)
return maintenance_io_concurrency;
else
return spc->opts->maintenance_io_concurrency;
}

View File

@ -196,6 +196,7 @@ static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource so
static bool check_max_wal_senders(int *newval, void **extra, GucSource source);
static bool check_autovacuum_work_mem(int *newval, void **extra, GucSource source);
static bool check_effective_io_concurrency(int *newval, void **extra, GucSource source);
static bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source);
static void assign_pgstat_temp_directory(const char *newval, void *extra);
static bool check_application_name(char **newval, void **extra, GucSource source);
static void assign_application_name(const char *newval, void *extra);
@ -2884,6 +2885,24 @@ static struct config_int ConfigureNamesInt[] =
check_effective_io_concurrency, NULL, NULL
},
{
{"maintenance_io_concurrency",
PGC_USERSET,
RESOURCES_ASYNCHRONOUS,
gettext_noop("A variant of effective_io_concurrency that is used for maintenance work."),
NULL,
GUC_EXPLAIN
},
&maintenance_io_concurrency,
#ifdef USE_PREFETCH
10,
#else
0,
#endif
0, MAX_IO_CONCURRENCY,
check_maintenance_io_concurrency, NULL, NULL
},
{
{"backend_flush_after", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Number of pages after which previously performed writes are flushed to disk."),
@ -11466,6 +11485,19 @@ check_effective_io_concurrency(int *newval, void **extra, GucSource source)
return true;
}
static bool
check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
{
#ifndef USE_PREFETCH
if (*newval != 0)
{
GUC_check_errdetail("maintenance_io_concurrency must be set to 0 on platforms that lack posix_fadvise().");
return false;
}
#endif /* USE_PREFETCH */
return true;
}
static void
assign_pgstat_temp_directory(const char *newval, void *extra)
{

View File

@ -2140,7 +2140,7 @@ psql_completion(const char *text, int start, int end)
/* ALTER TABLESPACE <foo> SET|RESET ( */
else if (Matches("ALTER", "TABLESPACE", MatchAny, "SET|RESET", "("))
COMPLETE_WITH("seq_page_cost", "random_page_cost",
"effective_io_concurrency");
"effective_io_concurrency", "maintenance_io_concurrency");
/* ALTER TEXT SEARCH */
else if (Matches("ALTER", "TEXT", "SEARCH"))

View File

@ -40,6 +40,7 @@ typedef struct TableSpaceOpts
float8 random_page_cost;
float8 seq_page_cost;
int effective_io_concurrency;
int maintenance_io_concurrency;
} TableSpaceOpts;
extern Oid CreateTableSpace(CreateTableSpaceStmt *stmt);

View File

@ -58,6 +58,7 @@ extern int bgwriter_lru_maxpages;
extern double bgwriter_lru_multiplier;
extern bool track_io_timing;
extern int effective_io_concurrency;
extern int maintenance_io_concurrency;
extern int checkpoint_flush_after;
extern int backend_flush_after;

View File

@ -16,5 +16,6 @@
void get_tablespace_page_costs(Oid spcid, float8 *spc_random_page_cost,
float8 *spc_seq_page_cost);
int get_tablespace_io_concurrency(Oid spcid);
int get_tablespace_maintenance_io_concurrency(Oid spcid);
#endif /* SPCCACHE_H */