Re: POC: Parallel processing of indexes in autovacuum - Mailing list pgsql-hackers

From Masahiko Sawada
Subject Re: POC: Parallel processing of indexes in autovacuum
Date
Msg-id CAD21AoCcHKKXsr9Oh736ejckqqS1i430xGEyJ=JP5OL0ExyP1A@mail.gmail.com
Whole thread Raw
In response to Re: POC: Parallel processing of indexes in autovacuum  (Daniil Davydov <3danissimo@gmail.com>)
List pgsql-hackers
On Mon, Jul 14, 2025 at 3:49 AM Daniil Davydov <3danissimo@gmail.com> wrote:
>
>
> > ---
> > +   nlaunched_workers = pvs->pcxt->nworkers_launched; /* remember this value */
> >     DestroyParallelContext(pvs->pcxt);
> > +
> > +   /* Release all launched (i.e. reserved) parallel autovacuum workers. */
> > +   if (AmAutoVacuumWorkerProcess())
> > +       ParallelAutoVacuumReleaseWorkers(nlaunched_workers);
> > +
> >
> > Why don't we release workers before destroying the parallel context?
> >
>
> Destroying parallel context includes waiting for all workers to exit (after
> which, other operations can use them).
> If we first call ParallelAutoVacuumReleaseWorkers, some operation can
> reasonably request all released workers. But this request can fail,
> because there is no guarantee that workers managed to finish.
>
> Actually, there's nothing wrong with that, but I think releasing workers
> only after finishing work is a more logical approach.
>



> > ---
> > @@ -706,16 +751,16 @@
> > parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int
> > num_index_scan
> >
> >         if (vacuum)
> >             ereport(pvs->shared->elevel,
> > -                   (errmsg(ngettext("launched %d parallel vacuum
> > worker for index vacuuming (planned: %d)",
> > -                                    "launched %d parallel vacuum
> > workers for index vacuuming (planned: %d)",
> > +                   (errmsg(ngettext("launched %d parallel %svacuum
> > worker for index vacuuming (planned: %d)",
> > +                                    "launched %d parallel %svacuum
> > workers for index vacuuming (planned: %d)",
> >                                      pvs->pcxt->nworkers_launched),
> > -                           pvs->pcxt->nworkers_launched, nworkers)));
> > +                           pvs->pcxt->nworkers_launched,
> > AmAutoVacuumWorkerProcess() ? "auto" : "", nworkers)));
> >
> > The "%svacuum" part doesn't work in terms of translation. We need to
> > construct the whole sentence instead.
> > But do we need this log message
> > change in the first place? IIUC autovacuums write logs only when the
> > execution time exceed the log_autovacuum_min_duration (or its
> > reloption). The patch unconditionally sets LOG level for autovacuums
> > but I'm not sure it's consistent with other autovacuum logging
> > behavior:
> >
> > +   int         elevel = AmAutoVacuumWorkerProcess() ||
> > +       vacrel->verbose ?
> > +       INFO : DEBUG2;
> >
> >
>
> This log level is used only "for messages about parallel workers launched".
> I think that such logs relate more to the parallel workers module than
> autovacuum itself. Moreover, if we emit log "planned vs. launched" each
> time, it will simplify the task of selecting the optimal value of
> 'autovacuum_max_parallel_workers' parameter. What do you think?

INFO level is normally not sent to the server log. And regarding
autovacuums, they don't write any log mentioning it started. If we
want to write planned vs. launched I think it's better to gather these
statistics during execution and write it together with other existing
logs.

>
> About "%svacuum" - I guess we need to clarify what exactly the workers
> were launched for. I'll add errhint to this log, but I don't know whether such
> approach is acceptable.

I'm not sure errhint is an appropriate place. If we write such
information together with other existing autovacuum logs as I
suggested above, I think we don't need to add such information to this
log message.

I've reviewed v7 patch and here are some comments:

+   {
+       {
+           "parallel_autovacuum_workers",
+           "Maximum number of parallel autovacuum workers that can be
taken from bgworkers pool for processing this table. "
+           "If value is 0 then parallel degree will computed based on
number of indexes.",
+           RELOPT_KIND_HEAP,
+           ShareUpdateExclusiveLock
+       },
+       -1, -1, 1024
+   },

Many autovacuum related reloptions have the prefix "autovacuum". So
how about renaming it to autovacuum_parallel_worker (change
check_parallel_av_gucs() name too accordingly)?

---
+bool
+check_autovacuum_max_parallel_workers(int *newval, void **extra,
+                                     GucSource source)
+{
+   if (*newval >= max_worker_processes)
+       return false;
+   return true;
+}

I think we don't need to strictly check the
autovacuum_max_parallel_workers value. Instead, we can accept any
integer value but internally cap by max_worker_processes.

---
+/*
+ * Make sure that number of available parallel workers corresponds to the
+ * autovacuum_max_parallel_workers parameter (after it was changed).
+ */
+static void
+check_parallel_av_gucs(int prev_max_parallel_workers)
+{

I think this function doesn't just check the value but does adjust the
number of available workers, so how about
adjust_free_parallel_workers() or something along these lines?

---
+       /*
+        * Number of available workers must not exceed limit.
+        *
+        * Note, that if some parallel autovacuum workers are running at this
+        * moment, available workers number will not exceed limit after
+        * releasing them (see ParallelAutoVacuumReleaseWorkers).
+       */
+       AutoVacuumShmem->av_freeParallelWorkers =
+           autovacuum_max_parallel_workers;

I think the comment refers to the following code in
AutoVacuumReleaseParallelWorkers():

+   /*
+    * If autovacuum_max_parallel_workers variable was reduced during parallel
+    * autovacuum execution, we must cap available workers number by its new
+    * value.
+    */
+   if (AutoVacuumShmem->av_freeParallelWorkers >
+       autovacuum_max_parallel_workers)
+   {
+       AutoVacuumShmem->av_freeParallelWorkers =
+           autovacuum_max_parallel_workers;
+   }

After the autovacuum launchers decreases av_freeParallelWorkers, it's
not guaranteed that the autovacuum worker already reflects the new
value from the config file when executing the
AutoVacuumReleaseParallelWorkers(), which leds to skips the above
codes. For example, suppose that autovacuum_max_parallel_workers is 10
and 3 parallel workers are running by one autovacuum worker (i.e.,
av_freeParallelWorkers = 7 now), if the user changes
autovacuum_max_parallel_workers to 5, the autovacuum launchers adjust
av_freeParallelWorkers to 5. However, if the worker doesn't reload the
config file and executes AutoVacuumReleaseParallelWorkers(), it
increases av_freeParallelWorkers to 8 and skips the adjusting logic.
I've not tested this scenarios so I might be missing something though.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com



pgsql-hackers by date:

Previous
From: Peter Geoghegan
Date:
Subject: Re: Returning nbtree posting list TIDs in DESC order during backwards scans
Next
From: Masahiko Sawada
Date:
Subject: Re: Make COPY format extendable: Extract COPY TO format implementations