@ -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,8 +862,27 @@ 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 .
*/
@ -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