On 11/06/2016 23:37, Julien Rouhaud wrote:
> On 09/06/2016 16:04, Robert Haas wrote:
>>
>> OK, I pushed this after re-reviewing it and fixing a number of
>> oversights.  There remains only the task of adding max_parallel_degree
>> as a system-wide limit (as opposed to max_parallel_degree now
>> max_parallel_workers_per_gather which is a per-Gather limit), which
>> I'm going to argue should be a new open item and not necessarily one
>> that I have to own myself.  I would like to take care of it, but I
>> will not put it ahead of fixing actual defects and I will not promise
>> to have it done in time for 9.6.
>>
> 
> PFA a patch to fix this open item.  I used the GUC name provided in the
> 9.6 open item page (max_parallel_workers), with a default value of 4.
> Value 0 is another way to disable parallel query.
> 

Sorry I just realized I made a stupid mistake, I didn't check in all
slots to get the number of active parallel workers. Fixed in attached v2.

-- 
Julien Rouhaud
http://dalibo.com - http://dalibo.org
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'
        </listitem>
       </varlistentry>
 
+      <varlistentry id="guc-max-parallel-workers" 
xreflabel="max_parallel_workers">
+       <term><varname>max_parallel_workers</varname> (<type>integer</type>)
+       <indexterm>
+        <primary><varname>max_parallel_workers</> configuration 
parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         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.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry id="guc-backend-flush-after" 
xreflabel="backend_flush_after">
        <term><varname>backend_flush_after</varname> (<type>integer</type>)
        <indexterm>
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,
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to