diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index e0e5a1e..c661c7a 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2018,6 +2018,23 @@ include_dir 'conf.d' + + max_parallel_workers (integer) + + max_parallel_workers configuration parameter + + + + + Sets the maximum number of workers that can be launched at the same + time for the whole server. This parameter allows the administrator to + reserve background worker slots for for third part dynamic background + workers. The default value is 4. Setting this value to 0 disables + parallel query execution. + + + + backend_flush_after (integer) diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index ab5ef25..7b53b53 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -473,8 +473,8 @@ LaunchParallelWorkers(ParallelContext *pcxt) { memcpy(worker.bgw_extra, &i, sizeof(int)); if (!any_registrations_failed && - RegisterDynamicBackgroundWorker(&worker, - &pcxt->worker[i].bgwhandle)) + RegisterDynamicBackgroundWorkerInternal(&worker, + &pcxt->worker[i].bgwhandle, true)) { shm_mq_set_handle(pcxt->worker[i].error_mqh, pcxt->worker[i].bgwhandle); diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index cc8ba61..2bcd86b 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -719,9 +719,11 @@ create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel) } /* - * In no case use more than max_parallel_workers_per_gather workers. + * In no case use more than max_parallel_workers or + * max_parallel_workers_per_gather workers. */ - parallel_workers = Min(parallel_workers, max_parallel_workers_per_gather); + parallel_workers = Min(max_parallel_workers, Min(parallel_workers, + max_parallel_workers_per_gather)); /* If any limit was set to zero, the user doesn't want a parallel scan. */ if (parallel_workers <= 0) diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index e7f63f4..fd62126 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -113,6 +113,7 @@ int effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE; Cost disable_cost = 1.0e10; +int max_parallel_workers = 4; int max_parallel_workers_per_gather = 2; bool enable_seqscan = true; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 54c0440..81d124c 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -246,8 +246,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) IsUnderPostmaster && dynamic_shared_memory_type != DSM_IMPL_NONE && parse->commandType == CMD_SELECT && !parse->hasModifyingCTE && parse->utilityStmt == NULL && max_parallel_workers_per_gather > 0 && - !IsParallelWorker() && !IsolationIsSerializable() && - !has_parallel_hazard((Node *) parse, true); + max_parallel_workers > 0 && !IsParallelWorker() && + !IsolationIsSerializable() && !has_parallel_hazard((Node *) parse, + true); /* * glob->parallelModeNeeded should tell us whether it's necessary to diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 382edad..6bef674 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -16,6 +16,7 @@ #include "miscadmin.h" #include "libpq/pqsignal.h" +#include "optimizer/cost.h" #include "postmaster/bgworker_internals.h" #include "postmaster/postmaster.h" #include "storage/barrier.h" @@ -76,6 +77,7 @@ typedef struct BackgroundWorkerSlot bool terminate; pid_t pid; /* InvalidPid = not started yet; 0 = dead */ uint64 generation; /* incremented when slot is recycled */ + bool parallel; BackgroundWorker worker; } BackgroundWorkerSlot; @@ -819,12 +821,16 @@ RegisterBackgroundWorker(BackgroundWorker *worker) * free this pointer using pfree(), if desired. */ bool -RegisterDynamicBackgroundWorker(BackgroundWorker *worker, - BackgroundWorkerHandle **handle) +RegisterDynamicBackgroundWorkerInternal(BackgroundWorker *worker, + BackgroundWorkerHandle **handle, + bool parallel) { int slotno; bool success = false; + bool create_worker = false; + int freeslot; uint64 generation = 0; + int n_active_parallel_workers = 0; /* * We can't register dynamic background workers from the postmaster. If @@ -843,30 +849,51 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker, LWLockAcquire(BackgroundWorkerLock, LW_EXCLUSIVE); /* - * Look for an unused slot. If we find one, grab it. + * Look for an unused slot. If we find one, grab it. In case of parallel + * worker, check in all slots if we didn't exhaust the number of allowed + * parallel workers */ for (slotno = 0; slotno < BackgroundWorkerData->total_slots; ++slotno) { BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno]; + if (slot->in_use && slot->parallel) + n_active_parallel_workers++; + + if (parallel && n_active_parallel_workers >= max_parallel_workers) + { + create_worker = false; + break; + } if (!slot->in_use) { - memcpy(&slot->worker, worker, sizeof(BackgroundWorker)); - slot->pid = InvalidPid; /* indicates not started yet */ - slot->generation++; - slot->terminate = false; - generation = slot->generation; + freeslot = slotno; + create_worker = true; + /* No need to check all slots if not asked for a parallel worker */ + if (!parallel) + break; + } + } - /* - * Make sure postmaster doesn't see the slot as in use before it - * sees the new contents. - */ - pg_write_barrier(); + if (create_worker) + { + BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[freeslot]; - slot->in_use = true; - success = true; - break; - } + memcpy(&slot->worker, worker, sizeof(BackgroundWorker)); + slot->pid = InvalidPid; /* indicates not started yet */ + slot->generation++; + slot->terminate = false; + slot->parallel = parallel; + generation = slot->generation; + + /* + * Make sure postmaster doesn't see the slot as in use before it + * sees the new contents. + */ + pg_write_barrier(); + + slot->in_use = true; + success = true; } LWLockRelease(BackgroundWorkerLock); @@ -881,13 +908,21 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker, if (success && handle) { *handle = palloc(sizeof(BackgroundWorkerHandle)); - (*handle)->slot = slotno; + (*handle)->slot = freeslot; (*handle)->generation = generation; } return success; } +bool +RegisterDynamicBackgroundWorker(BackgroundWorker *worker, + BackgroundWorkerHandle **handle) +{ + /* public API, not a parallel worker */ + return RegisterDynamicBackgroundWorkerInternal(worker, handle, false); +} + /* * Get the PID of a dynamically-registered background worker. * diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 9b02111..18fa5b5 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2657,6 +2657,16 @@ static struct config_int ConfigureNamesInt[] = }, { + {"max_parallel_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS, + gettext_noop("Sets the maximum number of parallel processes for the cluster."), + NULL + }, + &max_parallel_workers, + 2, 0, 1024, + NULL, NULL, NULL + }, + + { {"autovacuum_work_mem", PGC_SIGHUP, RESOURCES_MEM, gettext_noop("Sets the maximum memory to be used by each autovacuum worker process."), NULL, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 8260e37..7f16050 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -168,6 +168,7 @@ #effective_io_concurrency = 1 # 1-1000; 0 disables prefetching #max_worker_processes = 8 # (change requires restart) #max_parallel_workers_per_gather = 2 # taken from max_worker_processes +#max_parallel_workers = 4 # total maximum number of worker_processes #old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate # (change requires restart) #backend_flush_after = 0 # 0 disables, default is 0 diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index f41f9e9..eca5c1e 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -55,6 +55,7 @@ extern PGDLLIMPORT double parallel_setup_cost; extern PGDLLIMPORT int effective_cache_size; extern Cost disable_cost; extern int max_parallel_workers_per_gather; +extern int max_parallel_workers; extern bool enable_seqscan; extern bool enable_indexscan; extern bool enable_indexonlyscan; diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index b6889a3..958bc57 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -107,6 +107,9 @@ extern void RegisterBackgroundWorker(BackgroundWorker *worker); /* Register a new bgworker from a regular backend */ extern bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle); +extern bool RegisterDynamicBackgroundWorkerInternal(BackgroundWorker *worker, + BackgroundWorkerHandle **handle, + bool parallel); /* Query the status of a bgworker */ extern BgwHandleStatus GetBackgroundWorkerPid(BackgroundWorkerHandle *handle,