Skip to content

Commit

Permalink
Don't enter parallel mode when holding interrupts.
Browse files Browse the repository at this point in the history
Doing so caused the leader to hang in wait_event=ParallelFinish, which
required an immediate shutdown to resolve.  Back-patch to v12 (all
supported versions).

Francesco Degrassi

Discussion: https://postgr.es/m/CAC-SaSzHUKT=vZJ8MPxYdC_URPfax+yoA1hKTcF4ROz_Q6z0_Q@mail.gmail.com
  • Loading branch information
nmisch committed Sep 18, 2024
1 parent 7db9bfc commit 2370582
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/backend/optimizer/plan/planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
* we want to allow parallel inserts in general; updates and deletes have
* additional problems especially around combo CIDs.)
*
* We don't try to use parallel mode unless interruptible. The leader
* expects ProcessInterrupts() calls to reach HandleParallelMessages().
* Even if we called HandleParallelMessages() another way, starting a
* parallel worker is too delay-prone to be prudent when uncancellable.
*
* For now, we don't try to use parallel mode if we're running inside a
* parallel worker. We might eventually be able to relax this
* restriction, but for now it seems best not to have parallel workers
Expand All @@ -350,6 +355,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
parse->commandType == CMD_SELECT &&
!parse->hasModifyingCTE &&
max_parallel_workers_per_gather > 0 &&
INTERRUPTS_CAN_BE_PROCESSED() &&
!IsParallelWorker())
{
/* all the cheap tests pass, so scan the query tree */
Expand Down
24 changes: 24 additions & 0 deletions src/test/regress/expected/select_parallel.out
Original file line number Diff line number Diff line change
Expand Up @@ -1327,3 +1327,27 @@ reset debug_parallel_query;
drop function set_and_report_role();
drop function set_role_and_error(int);
drop role regress_parallel_worker;
-- don't freeze in ParallelFinish while holding an LWLock
BEGIN;
CREATE FUNCTION my_cmp (int4, int4)
RETURNS int LANGUAGE sql AS
$$
SELECT
CASE WHEN $1 < $2 THEN -1
WHEN $1 > $2 THEN 1
ELSE 0
END;
$$;
CREATE TABLE parallel_hang (i int4);
INSERT INTO parallel_hang
(SELECT * FROM generate_series(1, 400) gs);
CREATE OPERATOR CLASS int4_custom_ops FOR TYPE int4 USING btree AS
OPERATOR 1 < (int4, int4), OPERATOR 2 <= (int4, int4),
OPERATOR 3 = (int4, int4), OPERATOR 4 >= (int4, int4),
OPERATOR 5 > (int4, int4), FUNCTION 1 my_cmp(int4, int4);
CREATE UNIQUE INDEX parallel_hang_idx
ON parallel_hang
USING btree (i int4_custom_ops);
SET debug_parallel_query = on;
DELETE FROM parallel_hang WHERE 380 <= i AND i <= 420;
ROLLBACK;
31 changes: 31 additions & 0 deletions src/test/regress/sql/select_parallel.sql
Original file line number Diff line number Diff line change
Expand Up @@ -519,3 +519,34 @@ reset debug_parallel_query;
drop function set_and_report_role();
drop function set_role_and_error(int);
drop role regress_parallel_worker;

-- don't freeze in ParallelFinish while holding an LWLock
BEGIN;

CREATE FUNCTION my_cmp (int4, int4)
RETURNS int LANGUAGE sql AS
$$
SELECT
CASE WHEN $1 < $2 THEN -1
WHEN $1 > $2 THEN 1
ELSE 0
END;
$$;

CREATE TABLE parallel_hang (i int4);
INSERT INTO parallel_hang
(SELECT * FROM generate_series(1, 400) gs);

CREATE OPERATOR CLASS int4_custom_ops FOR TYPE int4 USING btree AS
OPERATOR 1 < (int4, int4), OPERATOR 2 <= (int4, int4),
OPERATOR 3 = (int4, int4), OPERATOR 4 >= (int4, int4),
OPERATOR 5 > (int4, int4), FUNCTION 1 my_cmp(int4, int4);

CREATE UNIQUE INDEX parallel_hang_idx
ON parallel_hang
USING btree (i int4_custom_ops);

SET debug_parallel_query = on;
DELETE FROM parallel_hang WHERE 380 <= i AND i <= 420;

ROLLBACK;

0 comments on commit 2370582

Please sign in to comment.