115
115
* GUC parameters
116
116
*/
117
117
bool autovacuum_start_daemon = false;
118
+ int autovacuum_worker_slots ;
118
119
int autovacuum_max_workers ;
119
120
int autovacuum_work_mem = -1 ;
120
121
int autovacuum_naptime ;
@@ -210,7 +211,7 @@ typedef struct autovac_table
210
211
/*-------------
211
212
* This struct holds information about a single worker's whereabouts. We keep
212
213
* an array of these in shared memory, sized according to
213
- * autovacuum_max_workers .
214
+ * autovacuum_worker_slots .
214
215
*
215
216
* wi_links entry into free list or running list
216
217
* wi_dboid OID of the database this worker is supposed to work on
@@ -291,7 +292,7 @@ typedef struct
291
292
{
292
293
sig_atomic_t av_signal [AutoVacNumSignals ];
293
294
pid_t av_launcherpid ;
294
- dlist_head av_freeWorkers ;
295
+ dclist_head av_freeWorkers ;
295
296
dlist_head av_runningWorkers ;
296
297
WorkerInfo av_startingWorker ;
297
298
AutoVacuumWorkItem av_workItems [NUM_WORKITEMS ];
@@ -349,6 +350,8 @@ static void autovac_report_activity(autovac_table *tab);
349
350
static void autovac_report_workitem (AutoVacuumWorkItem * workitem ,
350
351
const char * nspname , const char * relname );
351
352
static void avl_sigusr2_handler (SIGNAL_ARGS );
353
+ static bool av_worker_available (void );
354
+ static void check_av_worker_gucs (void );
352
355
353
356
354
357
@@ -577,8 +580,7 @@ AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
577
580
* wakening conditions.
578
581
*/
579
582
580
- launcher_determine_sleep (!dlist_is_empty (& AutoVacuumShmem -> av_freeWorkers ),
581
- false, & nap );
583
+ launcher_determine_sleep (av_worker_available (), false, & nap );
582
584
583
585
/*
584
586
* 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)
638
640
current_time = GetCurrentTimestamp ();
639
641
LWLockAcquire (AutovacuumLock , LW_SHARED );
640
642
641
- can_launch = ! dlist_is_empty ( & AutoVacuumShmem -> av_freeWorkers );
643
+ can_launch = av_worker_available ( );
642
644
643
645
if (AutoVacuumShmem -> av_startingWorker != NULL )
644
646
{
@@ -681,8 +683,8 @@ AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
681
683
worker -> wi_sharedrel = false;
682
684
worker -> wi_proc = NULL ;
683
685
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 );
686
688
AutoVacuumShmem -> av_startingWorker = NULL ;
687
689
ereport (WARNING ,
688
690
errmsg ("autovacuum worker took too long to start; canceled" ));
@@ -747,13 +749,23 @@ HandleAutoVacLauncherInterrupts(void)
747
749
748
750
if (ConfigReloadPending )
749
751
{
752
+ int autovacuum_max_workers_prev = autovacuum_max_workers ;
753
+
750
754
ConfigReloadPending = false;
751
755
ProcessConfigFile (PGC_SIGHUP );
752
756
753
757
/* shutdown requested in config file? */
754
758
if (!AutoVacuumingActive ())
755
759
AutoVacLauncherShutdown ();
756
760
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
+
757
769
/* rebuild the list in case the naptime changed */
758
770
rebuild_database_list (InvalidOid );
759
771
}
@@ -1089,7 +1101,7 @@ do_start_worker(void)
1089
1101
1090
1102
/* return quickly when there are no free workers */
1091
1103
LWLockAcquire (AutovacuumLock , LW_SHARED );
1092
- if (dlist_is_empty ( & AutoVacuumShmem -> av_freeWorkers ))
1104
+ if (! av_worker_available ( ))
1093
1105
{
1094
1106
LWLockRelease (AutovacuumLock );
1095
1107
return InvalidOid ;
@@ -1242,7 +1254,7 @@ do_start_worker(void)
1242
1254
* Get a worker entry from the freelist. We checked above, so there
1243
1255
* really should be a free slot.
1244
1256
*/
1245
- wptr = dlist_pop_head_node (& AutoVacuumShmem -> av_freeWorkers );
1257
+ wptr = dclist_pop_head_node (& AutoVacuumShmem -> av_freeWorkers );
1246
1258
1247
1259
worker = dlist_container (WorkerInfoData , wi_links , wptr );
1248
1260
worker -> wi_dboid = avdb -> adw_datid ;
@@ -1615,8 +1627,8 @@ FreeWorkerInfo(int code, Datum arg)
1615
1627
MyWorkerInfo -> wi_proc = NULL ;
1616
1628
MyWorkerInfo -> wi_launchtime = 0 ;
1617
1629
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 );
1620
1632
/* not mine anymore */
1621
1633
MyWorkerInfo = NULL ;
1622
1634
@@ -3248,10 +3260,14 @@ AutoVacuumRequestWork(AutoVacuumWorkItemType type, Oid relationId,
3248
3260
void
3249
3261
autovac_init (void )
3250
3262
{
3251
- if (autovacuum_start_daemon && !pgstat_track_counts )
3263
+ if (!autovacuum_start_daemon )
3264
+ return ;
3265
+ else if (!pgstat_track_counts )
3252
3266
ereport (WARNING ,
3253
3267
(errmsg ("autovacuum not started because of misconfiguration" ),
3254
3268
errhint ("Enable the \"track_counts\" option." )));
3269
+ else
3270
+ check_av_worker_gucs ();
3255
3271
}
3256
3272
3257
3273
/*
@@ -3268,7 +3284,7 @@ AutoVacuumShmemSize(void)
3268
3284
*/
3269
3285
size = sizeof (AutoVacuumShmemStruct );
3270
3286
size = MAXALIGN (size );
3271
- size = add_size (size , mul_size (autovacuum_max_workers ,
3287
+ size = add_size (size , mul_size (autovacuum_worker_slots ,
3272
3288
sizeof (WorkerInfoData )));
3273
3289
return size ;
3274
3290
}
@@ -3295,7 +3311,7 @@ AutoVacuumShmemInit(void)
3295
3311
Assert (!found );
3296
3312
3297
3313
AutoVacuumShmem -> av_launcherpid = 0 ;
3298
- dlist_init (& AutoVacuumShmem -> av_freeWorkers );
3314
+ dclist_init (& AutoVacuumShmem -> av_freeWorkers );
3299
3315
dlist_init (& AutoVacuumShmem -> av_runningWorkers );
3300
3316
AutoVacuumShmem -> av_startingWorker = NULL ;
3301
3317
memset (AutoVacuumShmem -> av_workItems , 0 ,
@@ -3305,10 +3321,10 @@ AutoVacuumShmemInit(void)
3305
3321
MAXALIGN (sizeof (AutoVacuumShmemStruct )));
3306
3322
3307
3323
/* initialize the WorkerInfo free list */
3308
- for (i = 0 ; i < autovacuum_max_workers ; i ++ )
3324
+ for (i = 0 ; i < autovacuum_worker_slots ; i ++ )
3309
3325
{
3310
- dlist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
3311
- & worker [i ].wi_links );
3326
+ dclist_push_head (& AutoVacuumShmem -> av_freeWorkers ,
3327
+ & worker [i ].wi_links );
3312
3328
pg_atomic_init_flag (& worker [i ].wi_dobalance );
3313
3329
}
3314
3330
@@ -3344,3 +3360,35 @@ check_autovacuum_work_mem(int *newval, void **extra, GucSource source)
3344
3360
3345
3361
return true;
3346
3362
}
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