115115 * GUC parameters
116116 */
117117bool autovacuum_start_daemon = false;
118+ int autovacuum_worker_slots ;
118119int autovacuum_max_workers ;
119120int autovacuum_work_mem = -1 ;
120121int autovacuum_naptime ;
@@ -210,7 +211,7 @@ typedef struct autovac_table
210211/*-------------
211212 * This struct holds information about a single worker's whereabouts. We keep
212213 * an array of these in shared memory, sized according to
213- * autovacuum_max_workers .
214+ * autovacuum_worker_slots .
214215 *
215216 * wi_links entry into free list or running list
216217 * wi_dboid OID of the database this worker is supposed to work on
@@ -291,7 +292,7 @@ typedef struct
291292{
292293 sig_atomic_t av_signal [AutoVacNumSignals ];
293294 pid_t av_launcherpid ;
294- dlist_head av_freeWorkers ;
295+ dclist_head av_freeWorkers ;
295296 dlist_head av_runningWorkers ;
296297 WorkerInfo av_startingWorker ;
297298 AutoVacuumWorkItem av_workItems [NUM_WORKITEMS ];
@@ -349,6 +350,8 @@ static void autovac_report_activity(autovac_table *tab);
349350static void autovac_report_workitem (AutoVacuumWorkItem * workitem ,
350351 const char * nspname , const char * relname );
351352static void avl_sigusr2_handler (SIGNAL_ARGS );
353+ static bool av_worker_available (void );
354+ static void check_av_worker_gucs (void );
352355
353356
354357
@@ -577,8 +580,7 @@ AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
577580 * wakening conditions.
578581 */
579582
580- launcher_determine_sleep (!dlist_is_empty (& AutoVacuumShmem -> av_freeWorkers ),
581- false, & nap );
583+ launcher_determine_sleep (av_worker_available (), false, & nap );
582584
583585 /*
584586 * Wait until naptime expires or we get some type of signal (all the
@@ -638,7 +640,7 @@ AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
638640 current_time = GetCurrentTimestamp ();
639641 LWLockAcquire (AutovacuumLock , LW_SHARED );
640642
641- can_launch = ! dlist_is_empty ( & AutoVacuumShmem -> av_freeWorkers );
643+ can_launch = av_worker_available ( );
642644
643645 if (AutoVacuumShmem -> av_startingWorker != NULL )
644646 {
@@ -681,8 +683,8 @@ AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
681683 worker -> wi_sharedrel = false;
682684 worker -> wi_proc = NULL ;
683685 worker -> wi_launchtime = 0 ;
684- dlist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
685- & worker -> wi_links );
686+ dclist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
687+ & worker -> wi_links );
686688 AutoVacuumShmem -> av_startingWorker = NULL ;
687689 ereport (WARNING ,
688690 errmsg ("autovacuum worker took too long to start; canceled" ));
@@ -747,13 +749,23 @@ HandleAutoVacLauncherInterrupts(void)
747749
748750 if (ConfigReloadPending )
749751 {
752+ int autovacuum_max_workers_prev = autovacuum_max_workers ;
753+
750754 ConfigReloadPending = false;
751755 ProcessConfigFile (PGC_SIGHUP );
752756
753757 /* shutdown requested in config file? */
754758 if (!AutoVacuumingActive ())
755759 AutoVacLauncherShutdown ();
756760
761+ /*
762+ * If autovacuum_max_workers changed, emit a WARNING if
763+ * autovacuum_worker_slots < autovacuum_max_workers. If it didn't
764+ * change, skip this to avoid too many repeated log messages.
765+ */
766+ if (autovacuum_max_workers_prev != autovacuum_max_workers )
767+ check_av_worker_gucs ();
768+
757769 /* rebuild the list in case the naptime changed */
758770 rebuild_database_list (InvalidOid );
759771 }
@@ -1089,7 +1101,7 @@ do_start_worker(void)
10891101
10901102 /* return quickly when there are no free workers */
10911103 LWLockAcquire (AutovacuumLock , LW_SHARED );
1092- if (dlist_is_empty ( & AutoVacuumShmem -> av_freeWorkers ))
1104+ if (! av_worker_available ( ))
10931105 {
10941106 LWLockRelease (AutovacuumLock );
10951107 return InvalidOid ;
@@ -1242,7 +1254,7 @@ do_start_worker(void)
12421254 * Get a worker entry from the freelist. We checked above, so there
12431255 * really should be a free slot.
12441256 */
1245- wptr = dlist_pop_head_node (& AutoVacuumShmem -> av_freeWorkers );
1257+ wptr = dclist_pop_head_node (& AutoVacuumShmem -> av_freeWorkers );
12461258
12471259 worker = dlist_container (WorkerInfoData , wi_links , wptr );
12481260 worker -> wi_dboid = avdb -> adw_datid ;
@@ -1615,8 +1627,8 @@ FreeWorkerInfo(int code, Datum arg)
16151627 MyWorkerInfo -> wi_proc = NULL ;
16161628 MyWorkerInfo -> wi_launchtime = 0 ;
16171629 pg_atomic_clear_flag (& MyWorkerInfo -> wi_dobalance );
1618- dlist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
1619- & MyWorkerInfo -> wi_links );
1630+ dclist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
1631+ & MyWorkerInfo -> wi_links );
16201632 /* not mine anymore */
16211633 MyWorkerInfo = NULL ;
16221634
@@ -3248,10 +3260,14 @@ AutoVacuumRequestWork(AutoVacuumWorkItemType type, Oid relationId,
32483260void
32493261autovac_init (void )
32503262{
3251- if (autovacuum_start_daemon && !pgstat_track_counts )
3263+ if (!autovacuum_start_daemon )
3264+ return ;
3265+ else if (!pgstat_track_counts )
32523266 ereport (WARNING ,
32533267 (errmsg ("autovacuum not started because of misconfiguration" ),
32543268 errhint ("Enable the \"track_counts\" option." )));
3269+ else
3270+ check_av_worker_gucs ();
32553271}
32563272
32573273/*
@@ -3268,7 +3284,7 @@ AutoVacuumShmemSize(void)
32683284 */
32693285 size = sizeof (AutoVacuumShmemStruct );
32703286 size = MAXALIGN (size );
3271- size = add_size (size , mul_size (autovacuum_max_workers ,
3287+ size = add_size (size , mul_size (autovacuum_worker_slots ,
32723288 sizeof (WorkerInfoData )));
32733289 return size ;
32743290}
@@ -3295,7 +3311,7 @@ AutoVacuumShmemInit(void)
32953311 Assert (!found );
32963312
32973313 AutoVacuumShmem -> av_launcherpid = 0 ;
3298- dlist_init (& AutoVacuumShmem -> av_freeWorkers );
3314+ dclist_init (& AutoVacuumShmem -> av_freeWorkers );
32993315 dlist_init (& AutoVacuumShmem -> av_runningWorkers );
33003316 AutoVacuumShmem -> av_startingWorker = NULL ;
33013317 memset (AutoVacuumShmem -> av_workItems , 0 ,
@@ -3305,10 +3321,10 @@ AutoVacuumShmemInit(void)
33053321 MAXALIGN (sizeof (AutoVacuumShmemStruct )));
33063322
33073323 /* initialize the WorkerInfo free list */
3308- for (i = 0 ; i < autovacuum_max_workers ; i ++ )
3324+ for (i = 0 ; i < autovacuum_worker_slots ; i ++ )
33093325 {
3310- dlist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
3311- & worker [i ].wi_links );
3326+ dclist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
3327+ & worker [i ].wi_links );
33123328 pg_atomic_init_flag (& worker [i ].wi_dobalance );
33133329 }
33143330
@@ -3344,3 +3360,35 @@ check_autovacuum_work_mem(int *newval, void **extra, GucSource source)
33443360
33453361 return true;
33463362}
3363+
3364+ /*
3365+ * Returns whether there is a free autovacuum worker slot available.
3366+ */
3367+ static bool
3368+ av_worker_available (void )
3369+ {
3370+ int free_slots ;
3371+ int reserved_slots ;
3372+
3373+ free_slots = dclist_count (& AutoVacuumShmem -> av_freeWorkers );
3374+
3375+ reserved_slots = autovacuum_worker_slots - autovacuum_max_workers ;
3376+ reserved_slots = Max (0 , reserved_slots );
3377+
3378+ return free_slots > reserved_slots ;
3379+ }
3380+
3381+ /*
3382+ * Emits a WARNING if autovacuum_worker_slots < autovacuum_max_workers.
3383+ */
3384+ static void
3385+ check_av_worker_gucs (void )
3386+ {
3387+ if (autovacuum_worker_slots < autovacuum_max_workers )
3388+ ereport (WARNING ,
3389+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
3390+ errmsg ("\"autovacuum_max_workers\" (%d) should be less than or equal to \"autovacuum_worker_slots\" (%d)" ,
3391+ autovacuum_max_workers , autovacuum_worker_slots ),
3392+ errdetail ("The server will only start up to \"autovacuum_worker_slots\" (%d) autovacuum workers at a given time." ,
3393+ autovacuum_worker_slots )));
3394+ }
0 commit comments