diff --git a/mysql-test/main/mdev-33070.cnf b/mysql-test/main/mdev-33070.cnf new file mode 100644 index 0000000000000..1c6cbae760dd6 --- /dev/null +++ b/mysql-test/main/mdev-33070.cnf @@ -0,0 +1,7 @@ +!include include/default_my.cnf + +[mysqld.1] +extra-port= @ENV.MASTER_EXTRA_PORT + +[ENV] +MASTER_EXTRA_PORT= @OPT.port diff --git a/mysql-test/main/mdev-33070.opt b/mysql-test/main/mdev-33070.opt new file mode 100644 index 0000000000000..0167dad78262b --- /dev/null +++ b/mysql-test/main/mdev-33070.opt @@ -0,0 +1 @@ +--thread-handling=pool-of-threads --loose-thread-pool-mode=generic --thread-pool-size=1 --thread-pool-max-threads=3 --thread-pool-oversubscribe=1 --thread-pool-stall-limit=10000 --thread-pool-dedicated-listener diff --git a/mysql-test/main/mdev-33070.result b/mysql-test/main/mdev-33070.result new file mode 100644 index 0000000000000..bfa27f9521f5f --- /dev/null +++ b/mysql-test/main/mdev-33070.result @@ -0,0 +1,41 @@ +# MDEV-33070 Thread pool starvation at oversubscribe threshold +CREATE TABLE t1 (a INT); +connect c1, localhost, root,,; +connect c2, localhost, root,,; +connect c3, localhost, root,,; +connect extra_con, 127.0.0.1, root,,test,$MASTER_EXTRA_PORT,; +connection c1; +SELECT SLEEP(1000); +connection extra_con; +connection c2; +SELECT SLEEP(1000); +connection extra_con; +connection c3; +INSERT INTO t1 VALUES (1); +connection extra_con; +SELECT SLEEP(1); +SLEEP(1) +0 +SELECT COUNT(*) = 0 FROM t1; +COUNT(*) = 0 +1 +KILL QUERY c1_id; +SELECT COUNT(*) = 1 FROM t1; +COUNT(*) = 1 +1 +connection c1; +disconnect c1; +connection extra_con; +KILL QUERY c2_id; +connection c2; +disconnect c2; +connection c3; +disconnect c3; +connection extra_con; +SELECT COUNT(*) = 1 FROM t1; +COUNT(*) = 1 +1 +disconnect extra_con; +connection default; +DROP TABLE t1; +# End of MDEV-33070 tests diff --git a/mysql-test/main/mdev-33070.test b/mysql-test/main/mdev-33070.test new file mode 100644 index 0000000000000..eafe8a28aafe2 --- /dev/null +++ b/mysql-test/main/mdev-33070.test @@ -0,0 +1,85 @@ +--source include/have_pool_of_threads.inc + +--echo # MDEV-33070 Thread pool starvation at oversubscribe threshold + +# The server is started with a single thread group, a dedicated listener, +# one worker thread, and thread_pool_oversubscribe=1. +# +# c1 and c2 run long queries and occupy the one worker plus the one allowed +# oversubscribe slot. c3 submits a trivial INSERT which the listener can only +# enqueue. +# +# Before the fix, after c1 was killed the worker stayed at the oversubscribe +# threshold and went to sleep instead of dequeuing c3. Because +# thread_pool_dedicated_listener=ON, only the worker can drain the queue, so if +# c3 is still pending while c1 and c2 run and completes only after c1 is +# killed, then the worker resumed dequeuing. + +CREATE TABLE t1 (a INT); + +--connect (c1, localhost, root,,) +--connect (c2, localhost, root,,) +--connect (c3, localhost, root,,) +--connect (extra_con, 127.0.0.1, root,,test,$MASTER_EXTRA_PORT,) + +--connection c1 +--let $c1_id= `SELECT CONNECTION_ID()` +--send SELECT SLEEP(1000) + +--connection extra_con +let $wait_condition= + SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE='User sleep' AND ID=$c1_id; +--source include/wait_condition.inc + +--connection c2 +--let $c2_id= `SELECT CONNECTION_ID()` +--send SELECT SLEEP(1000) + +--connection extra_con +let $wait_condition= + SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE='User sleep' AND ID=$c2_id; +--source include/wait_condition.inc + +--connection c3 +--send INSERT INTO t1 VALUES (1) + +--connection extra_con +SELECT SLEEP(1); +SELECT COUNT(*) = 0 FROM t1; + +--replace_result $c1_id c1_id +eval KILL QUERY $c1_id; + +let $wait_timeout= 2; +let $wait_condition= + SELECT COUNT(*) = 1 FROM t1; +--source include/wait_condition.inc +SELECT COUNT(*) = 1 FROM t1; + +--connection c1 +--error 0,ER_QUERY_INTERRUPTED,ER_STATEMENT_TIMEOUT +--reap +--disconnect c1 + +--connection extra_con +--replace_result $c2_id c2_id +eval KILL QUERY $c2_id; + +--connection c2 +--error 0,ER_QUERY_INTERRUPTED +--reap +--disconnect c2 + +--connection c3 +--reap +--disconnect c3 + +--connection extra_con +SELECT COUNT(*) = 1 FROM t1; +--disconnect extra_con + +--connection default +DROP TABLE t1; +--echo # End of MDEV-33070 tests diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index e9a3d96577480..d59fa0eee544b 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1140,7 +1140,7 @@ static void queue_put(thread_group_t *thread_group, TP_connection_generic *conne static bool too_many_threads(thread_group_t *thread_group) { - return (thread_group->active_thread_count >= 1+(int)threadpool_oversubscribe + return (thread_group->active_thread_count > 1+(int)threadpool_oversubscribe && !thread_group->stalled); }