@@ -80,9 +80,22 @@ typedef struct BackgroundWorkerSlot
8080 BackgroundWorker worker ;
8181} BackgroundWorkerSlot ;
8282
83+ /*
84+ * In order to limit the total number of parallel workers (according to
85+ * max_parallel_workers GUC), we maintain the number of active parallel
86+ * workers. Since the postmaster cannot take locks, two variables are used for
87+ * this purpose: the number of registered parallel workers (modified by the
88+ * backends, protected by BackgroundWorkerLock) and the number of terminated
89+ * parallel workers (modified only by the postmaster, lockless). The active
90+ * number of parallel workers is the number of registered workers minus the
91+ * terminated ones. These counters can of course overflow, but it's not
92+ * important here since the subtraction will still give the right number.
93+ */
8394typedef struct BackgroundWorkerArray
8495{
8596 int total_slots ;
97+ uint32 parallel_register_count ;
98+ uint32 parallel_terminate_count ;
8699 BackgroundWorkerSlot slot [FLEXIBLE_ARRAY_MEMBER ];
87100} BackgroundWorkerArray ;
88101
@@ -127,6 +140,8 @@ BackgroundWorkerShmemInit(void)
127140 int slotno = 0 ;
128141
129142 BackgroundWorkerData -> total_slots = max_worker_processes ;
143+ BackgroundWorkerData -> parallel_register_count = 0 ;
144+ BackgroundWorkerData -> parallel_terminate_count = 0 ;
130145
131146 /*
132147 * Copy contents of worker list into shared memory. Record the shared
@@ -267,9 +282,12 @@ BackgroundWorkerStateChange(void)
267282
268283 /*
269284 * We need a memory barrier here to make sure that the load of
270- * bgw_notify_pid completes before the store to in_use.
285+ * bgw_notify_pid and the update of parallel_terminate_count
286+ * complete before the store to in_use.
271287 */
272288 notify_pid = slot -> worker .bgw_notify_pid ;
289+ if ((slot -> worker .bgw_flags & BGWORKER_CLASS_PARALLEL ) != 0 )
290+ BackgroundWorkerData -> parallel_terminate_count ++ ;
273291 pg_memory_barrier ();
274292 slot -> pid = 0 ;
275293 slot -> in_use = false;
@@ -370,6 +388,9 @@ ForgetBackgroundWorker(slist_mutable_iter *cur)
370388
371389 Assert (rw -> rw_shmem_slot < max_worker_processes );
372390 slot = & BackgroundWorkerData -> slot [rw -> rw_shmem_slot ];
391+ if ((rw -> rw_worker .bgw_flags & BGWORKER_CLASS_PARALLEL ) != 0 )
392+ BackgroundWorkerData -> parallel_terminate_count ++ ;
393+
373394 slot -> in_use = false;
374395
375396 ereport (DEBUG1 ,
@@ -824,6 +845,7 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
824845{
825846 int slotno ;
826847 bool success = false;
848+ bool parallel ;
827849 uint64 generation = 0 ;
828850
829851 /*
@@ -840,8 +862,27 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
840862 if (!SanityCheckBackgroundWorker (worker , ERROR ))
841863 return false;
842864
865+ parallel = (worker -> bgw_flags & BGWORKER_CLASS_PARALLEL ) != 0 ;
866+
843867 LWLockAcquire (BackgroundWorkerLock , LW_EXCLUSIVE );
844868
869+ /*
870+ * If this is a parallel worker, check whether there are already too many
871+ * parallel workers; if so, don't register another one. Our view of
872+ * parallel_terminate_count may be slightly stale, but that doesn't really
873+ * matter: we would have gotten the same result if we'd arrived here
874+ * slightly earlier anyway. There's no help for it, either, since the
875+ * postmaster must not take locks; a memory barrier wouldn't guarantee
876+ * anything useful.
877+ */
878+ if (parallel && (BackgroundWorkerData -> parallel_register_count -
879+ BackgroundWorkerData -> parallel_terminate_count ) >=
880+ max_parallel_workers )
881+ {
882+ LWLockRelease (BackgroundWorkerLock );
883+ return false;
884+ }
885+
845886 /*
846887 * Look for an unused slot. If we find one, grab it.
847888 */
@@ -856,6 +897,8 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
856897 slot -> generation ++ ;
857898 slot -> terminate = false;
858899 generation = slot -> generation ;
900+ if (parallel )
901+ BackgroundWorkerData -> parallel_register_count ++ ;
859902
860903 /*
861904 * Make sure postmaster doesn't see the slot as in use before it
0 commit comments