diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 3cac340f32..672bf6f1ee 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2229,6 +2229,26 @@ include_dir 'conf.d' + + maintenance_io_concurrency (integer) + + maintenance_io_concurrency configuration parameter + + + + + Similar to effective_io_concurrency, but used + for maintenance work that is done on behalf of many client sessions. + + + 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 + ). + + + + max_worker_processes (integer) diff --git a/doc/src/sgml/ref/alter_tablespace.sgml b/doc/src/sgml/ref/alter_tablespace.sgml index acec33469f..356fb9f93f 100644 --- a/doc/src/sgml/ref/alter_tablespace.sgml +++ b/doc/src/sgml/ref/alter_tablespace.sgml @@ -84,13 +84,16 @@ ALTER TABLESPACE name RESET ( , , - ). This may be useful if + , + ). 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. diff --git a/doc/src/sgml/ref/create_tablespace.sgml b/doc/src/sgml/ref/create_tablespace.sgml index c621ec2c6b..462b8831c2 100644 --- a/doc/src/sgml/ref/create_tablespace.sgml +++ b/doc/src/sgml/ref/create_tablespace.sgml @@ -106,13 +106,16 @@ CREATE TABLESPACE tablespace_name A tablespace parameter to be set or reset. Currently, the only available parameters are seq_page_cost, - random_page_cost and effective_io_concurrency. - Setting either value for a particular tablespace will override the + random_page_cost, effective_io_concurrency + and maintenance_io_concurrency. + 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 , , - ). This may be useful if + , + ). 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. diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index c3d45c7a24..ec207d3b26 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -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, diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 5a32e62ed0..29694b8aa4 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -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); diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 7a7748b695..e05e2b3456 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -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. diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c index c4a0f719fb..e0c3c1b1c1 100644 --- a/src/backend/utils/cache/spccache.c +++ b/src/backend/utils/cache/spccache.c @@ -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; +} diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 326e773b25..68082315ac 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -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) { diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 174c3db623..ae35fa4aa9 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2140,7 +2140,7 @@ psql_completion(const char *text, int start, int end) /* ALTER TABLESPACE 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")) diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 41c457052d..fd1b28fca2 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -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); diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 2bf5afdade..d2a5b52f6e 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -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; diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h index 5112ba3c37..7e4ec69aa2 100644 --- a/src/include/utils/spccache.h +++ b/src/include/utils/spccache.h @@ -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 */