From 2c883a4abcf16331975fe42f9b56ccbc47ab8512 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Wed, 30 Sep 2026 12:52:56 +0530 Subject: [PATCH v1] Fall back to serial vacuum when out of DSM segments When no DSM segment can be created, InitializeParallelDSM() sets up the parallel context in backend-private memory with no workers, so that callers can carry on without parallelism. Parallel index builds then back out and build serially, and parallel queries run without workers. Parallel vacuum instead goes on to create a separate DSA area for its dead items in TidStoreCreateShared(), which needs another segment and fails with "too many dynamic shared memory segments". So VACUUM (PARALLEL) errors out where a serial vacuum would succeed, and a table set up for parallel autovacuum fails on every attempt for as long as the segments stay exhausted. Fix by backing out of parallel_vacuum_init() when no segment was created, like _bt_begin_parallel() does, so that the caller falls back to a serial vacuum with a local TidStore. The parallel context then always has workers past that point, so the check added by commit cc053b6e127 is no longer needed; revert it. Before commit 667e65aac35, the dead items were stored in the parallel vacuum DSM segment itself, so the fallback worked. Discussion: https://postgr.es/m/CALj2ACVjBN03Fq4XWgKH1zOfkapK6-P3ufNLHUHnZcW1zPm+Mg@mail.gmail.com --- src/backend/commands/vacuumparallel.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index d4572861000..db26f681677 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -391,6 +391,16 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, InitializeParallelDSM(pcxt); + /* If no DSM segment was available, back out (do serial vacuum) */ + if (pcxt->seg == NULL) + { + DestroyParallelContext(pcxt); + ExitParallelMode(); + pfree(will_parallel_vacuum); + pfree(pvs); + return NULL; + } + /* Prepare index vacuum stats */ indstats = (PVIndStats *) shm_toc_allocate(pcxt->toc, est_indstats_len); MemSet(indstats, 0, est_indstats_len); @@ -458,13 +468,9 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes, /* * Initialize shared cost-based vacuum delay parameters if it's for - * autovacuum and the parallel context has workers. Note that the parallel - * context falls back to the leader's private memory with no workers and - * no segment when the maximum number of DSM segments has been reached. - * There are then no workers to propagate the parameters to, and no - * segment to register the detach callback on. + * autovacuum. */ - if (shared->is_autovacuum && pcxt->nworkers > 0) + if (shared->is_autovacuum) { parallel_vacuum_set_cost_parameters(&shared->cost_params); pg_atomic_init_u32(&shared->cost_params.generation, 1); -- 2.34.1