Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+27-1
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

+2-2
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

+1-1
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

+65-17
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

+2-2
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

+3-3
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

+3-3
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

+10-1
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

+2-1
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

+1
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

+1
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)