@ -115,6 +115,7 @@
* GUC parameters
* GUC parameters
*/
*/
bool autovacuum_start_daemon = false ;
bool autovacuum_start_daemon = false ;
int autovacuum_worker_slots ;
int autovacuum_max_workers ;
int autovacuum_max_workers ;
int autovacuum_work_mem = - 1 ;
int autovacuum_work_mem = - 1 ;
int autovacuum_naptime ;
int autovacuum_naptime ;
@ -210,7 +211,7 @@ typedef struct autovac_table
/*-------------
/*-------------
* This struct holds information about a single worker ' s whereabouts . We keep
* This struct holds information about a single worker ' s whereabouts . We keep
* an array of these in shared memory , sized according to
* an array of these in shared memory , sized according to
* autovacuum_max_ workers .
* autovacuum_worker_slot s .
*
*
* wi_links entry into free list or running list
* wi_links entry into free list or running list
* wi_dboid OID of the database this worker is supposed to work on
* wi_dboid OID of the database this worker is supposed to work on
@ -291,7 +292,7 @@ typedef struct
{
{
sig_atomic_t av_signal [ AutoVacNumSignals ] ;
sig_atomic_t av_signal [ AutoVacNumSignals ] ;
pid_t av_launcherpid ;
pid_t av_launcherpid ;
dlist_head av_freeWorkers ;
dclist_head av_freeWorkers ;
dlist_head av_runningWorkers ;
dlist_head av_runningWorkers ;
WorkerInfo av_startingWorker ;
WorkerInfo av_startingWorker ;
AutoVacuumWorkItem av_workItems [ NUM_WORKITEMS ] ;
AutoVacuumWorkItem av_workItems [ NUM_WORKITEMS ] ;
@ -349,6 +350,8 @@ static void autovac_report_activity(autovac_table *tab);
static void autovac_report_workitem ( AutoVacuumWorkItem * workitem ,
static void autovac_report_workitem ( AutoVacuumWorkItem * workitem ,
const char * nspname , const char * relname ) ;
const char * nspname , const char * relname ) ;
static void avl_sigusr2_handler ( SIGNAL_ARGS ) ;
static void avl_sigusr2_handler ( SIGNAL_ARGS ) ;
static bool av_worker_available ( void ) ;
static void check_av_worker_gucs ( void ) ;
@ -577,8 +580,7 @@ AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
* wakening conditions .
* wakening conditions .
*/
*/
launcher_determine_sleep ( ! dlist_is_empty ( & AutoVacuumShmem - > av_freeWorkers ) ,
launcher_determine_sleep ( av_worker_available ( ) , false , & nap ) ;
false , & nap ) ;
/*
/*
* Wait until naptime expires or we get some type of signal ( all the
* 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)
current_time = GetCurrentTimestamp ( ) ;
current_time = GetCurrentTimestamp ( ) ;
LWLockAcquire ( AutovacuumLock , LW_SHARED ) ;
LWLockAcquire ( AutovacuumLock , LW_SHARED ) ;
can_launch = ! dlist_is_empty ( & AutoVacuumShmem - > av_freeWorkers ) ;
can_launch = av_worker_available ( ) ;
if ( AutoVacuumShmem - > av_startingWorker ! = NULL )
if ( AutoVacuumShmem - > av_startingWorker ! = NULL )
{
{
@ -681,8 +683,8 @@ AutoVacLauncherMain(char *startup_data, size_t startup_data_len)
worker - > wi_sharedrel = false ;
worker - > wi_sharedrel = false ;
worker - > wi_proc = NULL ;
worker - > wi_proc = NULL ;
worker - > wi_launchtime = 0 ;
worker - > wi_launchtime = 0 ;
dlist_push_head ( & AutoVacuumShmem - > av_freeWorkers ,
dc list_push_head ( & AutoVacuumShmem - > av_freeWorkers ,
& worker - > wi_links ) ;
& worker - > wi_links ) ;
AutoVacuumShmem - > av_startingWorker = NULL ;
AutoVacuumShmem - > av_startingWorker = NULL ;
ereport ( WARNING ,
ereport ( WARNING ,
errmsg ( " autovacuum worker took too long to start; canceled " ) ) ;
errmsg ( " autovacuum worker took too long to start; canceled " ) ) ;
@ -747,6 +749,8 @@ HandleAutoVacLauncherInterrupts(void)
if ( ConfigReloadPending )
if ( ConfigReloadPending )
{
{
int autovacuum_max_workers_prev = autovacuum_max_workers ;
ConfigReloadPending = false ;
ConfigReloadPending = false ;
ProcessConfigFile ( PGC_SIGHUP ) ;
ProcessConfigFile ( PGC_SIGHUP ) ;
@ -754,6 +758,14 @@ HandleAutoVacLauncherInterrupts(void)
if ( ! AutoVacuumingActive ( ) )
if ( ! AutoVacuumingActive ( ) )
AutoVacLauncherShutdown ( ) ;
AutoVacLauncherShutdown ( ) ;
/*
* If autovacuum_max_workers changed , emit a WARNING if
* autovacuum_worker_slots < autovacuum_max_workers . If it didn ' t
* change , skip this to avoid too many repeated log messages .
*/
if ( autovacuum_max_workers_prev ! = autovacuum_max_workers )
check_av_worker_gucs ( ) ;
/* rebuild the list in case the naptime changed */
/* rebuild the list in case the naptime changed */
rebuild_database_list ( InvalidOid ) ;
rebuild_database_list ( InvalidOid ) ;
}
}
@ -1089,7 +1101,7 @@ do_start_worker(void)
/* return quickly when there are no free workers */
/* return quickly when there are no free workers */
LWLockAcquire ( AutovacuumLock , LW_SHARED ) ;
LWLockAcquire ( AutovacuumLock , LW_SHARED ) ;
if ( dlist_is_empty ( & AutoVacuumShmem - > av_freeWorkers ) )
if ( ! av_worker_available ( ) )
{
{
LWLockRelease ( AutovacuumLock ) ;
LWLockRelease ( AutovacuumLock ) ;
return InvalidOid ;
return InvalidOid ;
@ -1242,7 +1254,7 @@ do_start_worker(void)
* Get a worker entry from the freelist . We checked above , so there
* Get a worker entry from the freelist . We checked above , so there
* really should be a free slot .
* really should be a free slot .
*/
*/
wptr = dlist_pop_head_node ( & AutoVacuumShmem - > av_freeWorkers ) ;
wptr = dc list_pop_head_node ( & AutoVacuumShmem - > av_freeWorkers ) ;
worker = dlist_container ( WorkerInfoData , wi_links , wptr ) ;
worker = dlist_container ( WorkerInfoData , wi_links , wptr ) ;
worker - > wi_dboid = avdb - > adw_datid ;
worker - > wi_dboid = avdb - > adw_datid ;
@ -1615,8 +1627,8 @@ FreeWorkerInfo(int code, Datum arg)
MyWorkerInfo - > wi_proc = NULL ;
MyWorkerInfo - > wi_proc = NULL ;
MyWorkerInfo - > wi_launchtime = 0 ;
MyWorkerInfo - > wi_launchtime = 0 ;
pg_atomic_clear_flag ( & MyWorkerInfo - > wi_dobalance ) ;
pg_atomic_clear_flag ( & MyWorkerInfo - > wi_dobalance ) ;
dlist_push_head ( & AutoVacuumShmem - > av_freeWorkers ,
dc list_push_head ( & AutoVacuumShmem - > av_freeWorkers ,
& MyWorkerInfo - > wi_links ) ;
& MyWorkerInfo - > wi_links ) ;
/* not mine anymore */
/* not mine anymore */
MyWorkerInfo = NULL ;
MyWorkerInfo = NULL ;
@ -3248,10 +3260,14 @@ AutoVacuumRequestWork(AutoVacuumWorkItemType type, Oid relationId,
void
void
autovac_init ( void )
autovac_init ( void )
{
{
if ( autovacuum_start_daemon & & ! pgstat_track_counts )
if ( ! autovacuum_start_daemon )
return ;
else if ( ! pgstat_track_counts )
ereport ( WARNING ,
ereport ( WARNING ,
( errmsg ( " autovacuum not started because of misconfiguration " ) ,
( errmsg ( " autovacuum not started because of misconfiguration " ) ,
errhint ( " Enable the \" track_counts \" option. " ) ) ) ;
errhint ( " Enable the \" track_counts \" option. " ) ) ) ;
else
check_av_worker_gucs ( ) ;
}
}
/*
/*
@ -3268,7 +3284,7 @@ AutoVacuumShmemSize(void)
*/
*/
size = sizeof ( AutoVacuumShmemStruct ) ;
size = sizeof ( AutoVacuumShmemStruct ) ;
size = MAXALIGN ( size ) ;
size = MAXALIGN ( size ) ;
size = add_size ( size , mul_size ( autovacuum_max_ workers ,
size = add_size ( size , mul_size ( autovacuum_worker_slot s ,
sizeof ( WorkerInfoData ) ) ) ;
sizeof ( WorkerInfoData ) ) ) ;
return size ;
return size ;
}
}
@ -3295,7 +3311,7 @@ AutoVacuumShmemInit(void)
Assert ( ! found ) ;
Assert ( ! found ) ;
AutoVacuumShmem - > av_launcherpid = 0 ;
AutoVacuumShmem - > av_launcherpid = 0 ;
dlist_init ( & AutoVacuumShmem - > av_freeWorkers ) ;
dc list_init ( & AutoVacuumShmem - > av_freeWorkers ) ;
dlist_init ( & AutoVacuumShmem - > av_runningWorkers ) ;
dlist_init ( & AutoVacuumShmem - > av_runningWorkers ) ;
AutoVacuumShmem - > av_startingWorker = NULL ;
AutoVacuumShmem - > av_startingWorker = NULL ;
memset ( AutoVacuumShmem - > av_workItems , 0 ,
memset ( AutoVacuumShmem - > av_workItems , 0 ,
@ -3305,10 +3321,10 @@ AutoVacuumShmemInit(void)
MAXALIGN ( sizeof ( AutoVacuumShmemStruct ) ) ) ;
MAXALIGN ( sizeof ( AutoVacuumShmemStruct ) ) ) ;
/* initialize the WorkerInfo free list */
/* initialize the WorkerInfo free list */
for ( i = 0 ; i < autovacuum_max_ workers ; i + + )
for ( i = 0 ; i < autovacuum_worker_slot s ; i + + )
{
{
dlist_push_head ( & AutoVacuumShmem - > av_freeWorkers ,
dc list_push_head ( & AutoVacuumShmem - > av_freeWorkers ,
& worker [ i ] . wi_links ) ;
& worker [ i ] . wi_links ) ;
pg_atomic_init_flag ( & worker [ i ] . wi_dobalance ) ;
pg_atomic_init_flag ( & worker [ i ] . wi_dobalance ) ;
}
}
@ -3344,3 +3360,35 @@ check_autovacuum_work_mem(int *newval, void **extra, GucSource source)
return true ;
return true ;
}
}
/*
* Returns whether there is a free autovacuum worker slot available .
*/
static bool
av_worker_available ( void )
{
int free_slots ;
int reserved_slots ;
free_slots = dclist_count ( & AutoVacuumShmem - > av_freeWorkers ) ;
reserved_slots = autovacuum_worker_slots - autovacuum_max_workers ;
reserved_slots = Max ( 0 , reserved_slots ) ;
return free_slots > reserved_slots ;
}
/*
* Emits a WARNING if autovacuum_worker_slots < autovacuum_max_workers .
*/
static void
check_av_worker_gucs ( void )
{
if ( autovacuum_worker_slots < autovacuum_max_workers )
ereport ( WARNING ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " \" autovacuum_max_workers \" (%d) should be less than or equal to \" autovacuum_worker_slots \" (%d) " ,
autovacuum_max_workers , autovacuum_worker_slots ) ,
errdetail ( " The server will only start up to \" autovacuum_worker_slots \" (%d) autovacuum workers at a given time. " ,
autovacuum_worker_slots ) ) ) ;
}