From 50c234fe5682e6013cf15f7fd588b077cf333aaf Mon Sep 17 00:00:00 2001 From: Jianghua Yang Date: Wed, 15 Jul 2026 17:30:20 +0800 Subject: [PATCH] Fix: disable parallel index build on QD and AO tables (#12) HNSW and IVFFlat manage their own parallel builds via plan_create_index_workers(), bypassing the guard in core's index_build() (catalog/index.c) that disables parallel index builds on the dispatcher and for AO tables. On the QD, the coordinator's empty, never-analyzed copy of the table still gets a 10-page default size estimate, so parallel workers can be launched (e.g. with min_parallel_table_scan_size lowered). Those workers are forced to GP_ROLE_EXECUTE by ParallelWorkerMain() and inherit QE-only globals (ic_htab_size, numsegmentsFromQD) from the QD leader, where both are 0. The worker then crashes: - assert builds: FailedAssertion("ht->size > 0") in initConnHashTable (contrib/interconnect/udp/ic_udpifc.c) - non-assert builds: "cannot access table ... in current transaction" from the numsegments sanity check in cdbcat.c Mirror the core guard in ComputeParallelWorkers() (hnsw) and AssignTuples() (ivfflat). Parallel builds on segments are unaffected: QE backends hand valid interconnect state to their workers, and each segment still uses parallel workers after this change. Fixes #12 --- src/hnswbuild.c | 10 ++++++++++ src/ivfbuild.c | 10 ++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/hnswbuild.c b/src/hnswbuild.c index b667478b..89c96ca7 100644 --- a/src/hnswbuild.c +++ b/src/hnswbuild.c @@ -45,6 +45,7 @@ #include "access/xloginsert.h" #include "catalog/index.h" #include "catalog/pg_type_d.h" +#include "cdb/cdbvars.h" #include "commands/progress.h" #include "hnsw.h" #include "miscadmin.h" @@ -1037,6 +1038,15 @@ ComputeParallelWorkers(Relation heap, Relation index) { int parallel_workers; + /* + * Follow index_build(): parallel workers launched on the QD inherit + * QE-only interconnect state (ic_htab_size, numsegmentsFromQD) that is + * unset in a dispatcher backend, so disable parallelism on the QD and + * for AO tables just like the core btree build path does. + */ + if (Gp_role == GP_ROLE_DISPATCH || AMHandlerIsAO(heap->rd_amhandler)) + return 0; + /* Make sure it's safe to use parallel workers */ parallel_workers = plan_create_index_workers(RelationGetRelid(heap), RelationGetRelid(index)); if (parallel_workers == 0) diff --git a/src/ivfbuild.c b/src/ivfbuild.c index ee2afd40..b8ab09a9 100644 --- a/src/ivfbuild.c +++ b/src/ivfbuild.c @@ -934,8 +934,14 @@ AssignTuples(IvfflatBuildState * buildstate) pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE, PROGRESS_IVFFLAT_PHASE_ASSIGN); - /* Calculate parallel workers */ - if (buildstate->heap != NULL) + /* + * Follow index_build(): parallel workers launched on the QD inherit + * QE-only interconnect state (ic_htab_size, numsegmentsFromQD) that is + * unset in a dispatcher backend, so disable parallelism on the QD and + * for AO tables just like the core btree build path does. + */ + if (buildstate->heap != NULL && Gp_role != GP_ROLE_DISPATCH && + !AMHandlerIsAO(buildstate->heap->rd_amhandler)) parallel_workers = plan_create_index_workers(RelationGetRelid(buildstate->heap), RelationGetRelid(buildstate->index)); /* Attempt to launch parallel worker scan when required */