aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/bgworker.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/bgworker.c')
-rw-r--r--src/backend/postmaster/bgworker.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 92495850db0..13a6e23a142 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -80,9 +80,22 @@ typedef struct BackgroundWorkerSlot
BackgroundWorker worker;
} BackgroundWorkerSlot;
+/*
+ * In order to limit the total number of parallel workers (according to
+ * max_parallel_workers GUC), we maintain the number of active parallel
+ * workers. Since the postmaster cannot take locks, two variables are used for
+ * this purpose: the number of registered parallel workers (modified by the
+ * backends, protected by BackgroundWorkerLock) and the number of terminated
+ * parallel workers (modified only by the postmaster, lockless). The active
+ * number of parallel workers is the number of registered workers minus the
+ * terminated ones. These counters can of course overflow, but it's not
+ * important here since the subtraction will still give the right number.
+ */
typedef struct BackgroundWorkerArray
{
int total_slots;
+ uint32 parallel_register_count;
+ uint32 parallel_terminate_count;
BackgroundWorkerSlot slot[FLEXIBLE_ARRAY_MEMBER];
} BackgroundWorkerArray;
@@ -127,6 +140,8 @@ BackgroundWorkerShmemInit(void)
int slotno = 0;
BackgroundWorkerData->total_slots = max_worker_processes;
+ BackgroundWorkerData->parallel_register_count = 0;
+ BackgroundWorkerData->parallel_terminate_count = 0;
/*
* Copy contents of worker list into shared memory. Record the shared
@@ -267,9 +282,12 @@ BackgroundWorkerStateChange(void)
/*
* We need a memory barrier here to make sure that the load of
- * bgw_notify_pid completes before the store to in_use.
+ * bgw_notify_pid and the update of parallel_terminate_count
+ * complete before the store to in_use.
*/
notify_pid = slot->worker.bgw_notify_pid;
+ if ((slot->worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0)
+ BackgroundWorkerData->parallel_terminate_count++;
pg_memory_barrier();
slot->pid = 0;
slot->in_use = false;
@@ -370,6 +388,9 @@ ForgetBackgroundWorker(slist_mutable_iter *cur)
Assert(rw->rw_shmem_slot < max_worker_processes);
slot = &BackgroundWorkerData->slot[rw->rw_shmem_slot];
+ if ((rw->rw_worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0)
+ BackgroundWorkerData->parallel_terminate_count++;
+
slot->in_use = false;
ereport(DEBUG1,
@@ -824,6 +845,7 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
{
int slotno;
bool success = false;
+ bool parallel;
uint64 generation = 0;
/*
@@ -840,9 +862,28 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
if (!SanityCheckBackgroundWorker(worker, ERROR))
return false;
+ parallel = (worker->bgw_flags & BGWORKER_CLASS_PARALLEL) != 0;
+
LWLockAcquire(BackgroundWorkerLock, LW_EXCLUSIVE);
/*
+ * If this is a parallel worker, check whether there are already too many
+ * parallel workers; if so, don't register another one. Our view of
+ * parallel_terminate_count may be slightly stale, but that doesn't really
+ * matter: we would have gotten the same result if we'd arrived here
+ * slightly earlier anyway. There's no help for it, either, since the
+ * postmaster must not take locks; a memory barrier wouldn't guarantee
+ * anything useful.
+ */
+ if (parallel && (BackgroundWorkerData->parallel_register_count -
+ BackgroundWorkerData->parallel_terminate_count) >=
+ max_parallel_workers)
+ {
+ LWLockRelease(BackgroundWorkerLock);
+ return false;
+ }
+
+ /*
* Look for an unused slot. If we find one, grab it.
*/
for (slotno = 0; slotno < BackgroundWorkerData->total_slots; ++slotno)
@@ -856,6 +897,8 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
slot->generation++;
slot->terminate = false;
generation = slot->generation;
+ if (parallel)
+ BackgroundWorkerData->parallel_register_count++;
/*
* Make sure postmaster doesn't see the slot as in use before it