Skip to content

Commit c758119

Browse files
Allow changing autovacuum_max_workers without restarting.
This commit introduces a new parameter named autovacuum_worker_slots that controls how many autovacuum worker slots to reserve during server startup. Modifying this new parameter's value does require a server restart, but it should typically be set to the upper bound of what you might realistically need to set autovacuum_max_workers. With that new parameter in place, autovacuum_max_workers can now be changed with a SIGHUP (e.g., pg_ctl reload). If autovacuum_max_workers is set higher than autovacuum_worker_slots, a WARNING is emitted, and the server will only start up to autovacuum_worker_slots workers at a given time. If autovacuum_max_workers is set to a value less than the number of currently-running autovacuum workers, the existing workers will continue running, but no new workers will be started until the number of running autovacuum workers drops below autovacuum_max_workers. Reviewed-by: Sami Imseih, Justin Pryzby, Robert Haas, Andres Freund, Yogesh Sharma Discussion: https://postgr.es/m/20240410212344.GA1824549%40nathanxps13
1 parent 5e68f61 commit c758119

File tree

11 files changed

+117
-31
lines changed

11 files changed

+117
-31
lines changed

doc/src/sgml/config.sgml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8630,6 +8630,25 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
86308630
</listitem>
86318631
</varlistentry>
86328632

8633+
<varlistentry id="guc-autovacuum-worker-slots" xreflabel="autovacuum_worker_slots">
8634+
<term><varname>autovacuum_worker_slots</varname> (<type>integer</type>)
8635+
<indexterm>
8636+
<primary><varname>autovacuum_worker_slots</varname> configuration parameter</primary>
8637+
</indexterm>
8638+
</term>
8639+
<listitem>
8640+
<para>
8641+
Specifies the number of backend slots to reserve for autovacuum worker
8642+
processes. The default is 16. This parameter can only be set at server
8643+
start.
8644+
</para>
8645+
<para>
8646+
When changing this value, consider also adjusting
8647+
<xref linkend="guc-autovacuum-max-workers"/>.
8648+
</para>
8649+
</listitem>
8650+
</varlistentry>
8651+
86338652
<varlistentry id="guc-autovacuum-max-workers" xreflabel="autovacuum_max_workers">
86348653
<term><varname>autovacuum_max_workers</varname> (<type>integer</type>)
86358654
<indexterm>
@@ -8640,7 +8659,14 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
86408659
<para>
86418660
Specifies the maximum number of autovacuum processes (other than the
86428661
autovacuum launcher) that may be running at any one time. The default
8643-
is three. This parameter can only be set at server start.
8662+
is three. This parameter can only be set in the
8663+
<filename>postgresql.conf</filename> file or on the server command line.
8664+
</para>
8665+
<para>
8666+
Note that a setting for this value which is higher than
8667+
<xref linkend="guc-autovacuum-worker-slots"/> will have no effect,
8668+
since autovacuum workers are taken from the pool of slots established
8669+
by that setting.
86448670
</para>
86458671
</listitem>
86468672
</varlistentry>

doc/src/sgml/runtime.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such
839839
When using System V semaphores,
840840
<productname>PostgreSQL</productname> uses one semaphore per allowed connection
841841
(<xref linkend="guc-max-connections"/>), allowed autovacuum worker process
842-
(<xref linkend="guc-autovacuum-max-workers"/>), allowed WAL sender process
842+
(<xref linkend="guc-autovacuum-worker-slots"/>), allowed WAL sender process
843843
(<xref linkend="guc-max-wal-senders"/>), allowed background
844844
process (<xref linkend="guc-max-worker-processes"/>), etc., in sets of 19.
845845
The runtime-computed parameter <xref linkend="guc-num-os-semaphores"/>
@@ -892,7 +892,7 @@ $ <userinput>postgres -D $PGDATA -C num_os_semaphores</userinput>
892892
When using POSIX semaphores, the number of semaphores needed is the
893893
same as for System V, that is one semaphore per allowed connection
894894
(<xref linkend="guc-max-connections"/>), allowed autovacuum worker process
895-
(<xref linkend="guc-autovacuum-max-workers"/>), allowed WAL sender process
895+
(<xref linkend="guc-autovacuum-worker-slots"/>), allowed WAL sender process
896896
(<xref linkend="guc-max-wal-senders"/>), allowed background
897897
process (<xref linkend="guc-max-worker-processes"/>), etc.
898898
On the platforms where this option is preferred, there is no specific

src/backend/access/transam/xlog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5403,7 +5403,7 @@ CheckRequiredParameterValues(void)
54035403
*/
54045404
if (ArchiveRecoveryRequested && EnableHotStandby)
54055405
{
5406-
/* We ignore autovacuum_max_workers when we make this test. */
5406+
/* We ignore autovacuum_worker_slots when we make this test. */
54075407
RecoveryRequiresIntParameter("max_connections",
54085408
MaxConnections,
54095409
ControlFile->MaxConnections);

src/backend/postmaster/autovacuum.c

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
* GUC parameters
116116
*/
117117
bool autovacuum_start_daemon = false;
118+
int autovacuum_worker_slots;
118119
int autovacuum_max_workers;
119120
int autovacuum_work_mem = -1;
120121
int 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);
349350
static void autovac_report_workitem(AutoVacuumWorkItem *workitem,
350351
const char *nspname, const char *relname);
351352
static 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,
32483260
void
32493261
autovac_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+
}

src/backend/postmaster/pmchild.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* child process is allocated a PMChild struct from a fixed pool of structs.
99
* The size of the pool is determined by various settings that configure how
1010
* many worker processes and backend connections are allowed, i.e.
11-
* autovacuum_max_workers, max_worker_processes, max_wal_senders, and
11+
* autovacuum_worker_slots, max_worker_processes, max_wal_senders, and
1212
* max_connections.
1313
*
1414
* Dead-end backends are handled slightly differently. There is no limit
@@ -99,7 +99,7 @@ InitPostmasterChildSlots(void)
9999
*/
100100
pmchild_pools[B_BACKEND].size = 2 * (MaxConnections + max_wal_senders);
101101

102-
pmchild_pools[B_AUTOVAC_WORKER].size = autovacuum_max_workers;
102+
pmchild_pools[B_AUTOVAC_WORKER].size = autovacuum_worker_slots;
103103
pmchild_pools[B_BG_WORKER].size = max_worker_processes;
104104

105105
/*

src/backend/storage/lmgr/proc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ ProcGlobalSemas(void)
150150
* So, now we grab enough semaphores to support the desired max number
151151
* of backends immediately at initialization --- if the sysadmin has set
152152
* MaxConnections, max_worker_processes, max_wal_senders, or
153-
* autovacuum_max_workers higher than his kernel will support, he'll
153+
* autovacuum_worker_slots higher than his kernel will support, he'll
154154
* find out sooner rather than later.
155155
*
156156
* Another reason for creating semaphores here is that the semaphore
@@ -284,13 +284,13 @@ InitProcGlobal(void)
284284
dlist_push_tail(&ProcGlobal->freeProcs, &proc->links);
285285
proc->procgloballist = &ProcGlobal->freeProcs;
286286
}
287-
else if (i < MaxConnections + autovacuum_max_workers + NUM_SPECIAL_WORKER_PROCS)
287+
else if (i < MaxConnections + autovacuum_worker_slots + NUM_SPECIAL_WORKER_PROCS)
288288
{
289289
/* PGPROC for AV or special worker, add to autovacFreeProcs list */
290290
dlist_push_tail(&ProcGlobal->autovacFreeProcs, &proc->links);
291291
proc->procgloballist = &ProcGlobal->autovacFreeProcs;
292292
}
293-
else if (i < MaxConnections + autovacuum_max_workers + NUM_SPECIAL_WORKER_PROCS + max_worker_processes)
293+
else if (i < MaxConnections + autovacuum_worker_slots + NUM_SPECIAL_WORKER_PROCS + max_worker_processes)
294294
{
295295
/* PGPROC for bgworker, add to bgworkerFreeProcs list */
296296
dlist_push_tail(&ProcGlobal->bgworkerFreeProcs, &proc->links);

src/backend/utils/init/postinit.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,15 +547,15 @@ InitializeMaxBackends(void)
547547
Assert(MaxBackends == 0);
548548

549549
/* Note that this does not include "auxiliary" processes */
550-
MaxBackends = MaxConnections + autovacuum_max_workers +
550+
MaxBackends = MaxConnections + autovacuum_worker_slots +
551551
max_worker_processes + max_wal_senders + NUM_SPECIAL_WORKER_PROCS;
552552

553553
if (MaxBackends > MAX_BACKENDS)
554554
ereport(ERROR,
555555
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
556556
errmsg("too many server processes configured"),
557-
errdetail("\"max_connections\" (%d) plus \"autovacuum_max_workers\" (%d) plus \"max_worker_processes\" (%d) plus \"max_wal_senders\" (%d) must be less than %d.",
558-
MaxConnections, autovacuum_max_workers,
557+
errdetail("\"max_connections\" (%d) plus \"autovacuum_worker_slots\" (%d) plus \"max_worker_processes\" (%d) plus \"max_wal_senders\" (%d) must be less than %d.",
558+
MaxConnections, autovacuum_worker_slots,
559559
max_worker_processes, max_wal_senders,
560560
MAX_BACKENDS - (NUM_SPECIAL_WORKER_PROCS - 1))));
561561
}

src/backend/utils/misc/guc_tables.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3467,7 +3467,16 @@ struct config_int ConfigureNamesInt[] =
34673467
},
34683468
{
34693469
/* see max_connections */
3470-
{"autovacuum_max_workers", PGC_POSTMASTER, AUTOVACUUM,
3470+
{"autovacuum_worker_slots", PGC_POSTMASTER, AUTOVACUUM,
3471+
gettext_noop("Sets the number of backend slots to allocate for autovacuum workers."),
3472+
NULL
3473+
},
3474+
&autovacuum_worker_slots,
3475+
16, 1, MAX_BACKENDS,
3476+
NULL, NULL, NULL
3477+
},
3478+
{
3479+
{"autovacuum_max_workers", PGC_SIGHUP, AUTOVACUUM,
34713480
gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes."),
34723481
NULL
34733482
},

src/backend/utils/misc/postgresql.conf.sample

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,8 +661,9 @@
661661

662662
#autovacuum = on # Enable autovacuum subprocess? 'on'
663663
# requires track_counts to also be on.
664-
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
664+
autovacuum_worker_slots = 16 # autovacuum worker slots to allocate
665665
# (change requires restart)
666+
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
666667
#autovacuum_naptime = 1min # time between autovacuum runs
667668
#autovacuum_vacuum_threshold = 50 # min number of row updates before
668669
# vacuum

src/include/postmaster/autovacuum.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typedef enum
2828

2929
/* GUC variables */
3030
extern PGDLLIMPORT bool autovacuum_start_daemon;
31+
extern PGDLLIMPORT int autovacuum_worker_slots;
3132
extern PGDLLIMPORT int autovacuum_max_workers;
3233
extern PGDLLIMPORT int autovacuum_work_mem;
3334
extern PGDLLIMPORT int autovacuum_naptime;

src/test/perl/PostgreSQL/Test/Cluster.pm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,7 @@ sub init
707707
}
708708
print $conf "max_wal_senders = 10\n";
709709
print $conf "max_replication_slots = 10\n";
710+
print $conf "autovacuum_worker_slots = 3\n";
710711
print $conf "wal_log_hints = on\n";
711712
print $conf "hot_standby = on\n";
712713
# conservative settings to ensure we can run multiple postmasters:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy