Commit c1e69a77 authored by unknown's avatar unknown

Avoid races in connect.test.

The problem was in a test case for Bug33507:
  - when the number of active connections reaches the limit,
    the server accepts only root connections. That's achieved by
    accepting a connection, negotiating with the client and
    checking user credentials. If it is not SUPER, the connection
    is dropped.
  - when the server accepts connection, it increases the counter;
  - when the server drops connection, it decreases the counter;
  - the race was in between of decreasing the counter and accepting
    new connection:
    - max_user_connections = 2;
    - 2 oridinary user connections accepted;
    - extra user connection is establishing;
    - server checked user credentials, and sent 'Too many connections'
      error;
    - the client receives the error and establishes extra SUPER user
      connection;
    - the server however didn't decrease the counter (the extra
      user connection still is "alive" in the server) -- so, the new
      SUPER-user connection, will be dropped, because it exceeds
      (max_user_connections + 1).

The fix is to implement "safe connect", which makes several attempts
to connect and use it in the test script.


mysql-test/r/connect.result:
  Update test file.
mysql-test/t/connect.test:
  Avoid races in connect.test.
mysql-test/include/connect2.inc:
  Auxiliary routine to establish a connection reliably.
parent 30d644f8
# include/connect2.inc
#
# SUMMARY
#
# Make several attempts to connect.
#
# USAGE
#
# EXAMPLE
#
# connect.test
#
--disable_query_log
let $wait_counter= 300;
if ($wait_timeout)
{
let $wait_counter= `SELECT $wait_timeout * 10`;
}
# Reset $wait_timeout so that its value won't be used on subsequent
# calls, and default will be used instead.
let $wait_timeout= 0;
--echo # -- Establishing connection '$con_name' (user: $con_user_name)...
while ($wait_counter)
{
--disable_abort_on_error
--disable_result_log
--connect ($con_name,localhost,$con_user_name)
--enable_result_log
--enable_abort_on_error
let $error = $mysql_errno;
if (!$error)
{
let $wait_counter= 0;
}
if ($error)
{
real_sleep 0.1;
dec $wait_counter;
}
}
if ($error)
{
--echo # -- Error: can not establish connection '$con_name'.
}
if (!$error)
{
--echo # -- Connection '$con_name' has been established.
}
--enable_query_log
...@@ -127,8 +127,7 @@ GRANT USAGE ON *.* TO mysqltest_u1@localhost; ...@@ -127,8 +127,7 @@ GRANT USAGE ON *.* TO mysqltest_u1@localhost;
SET GLOBAL max_connections = 3; SET GLOBAL max_connections = 3;
SET GLOBAL event_scheduler = ON; SET GLOBAL event_scheduler = ON;
# -- Waiting for old connections to close... # -- Waiting for Event Scheduler to start...
# -- Disconnecting default connection... # -- Disconnecting default connection...
...@@ -136,22 +135,33 @@ SET GLOBAL event_scheduler = ON; ...@@ -136,22 +135,33 @@ SET GLOBAL event_scheduler = ON;
# -- many threads are running. # -- many threads are running.
# -- Connecting (1)... # -- Connecting (1)...
# -- Establishing connection 'con_1' (user: mysqltest_u1)...
# -- Waiting for root connection to close... # -- Connection 'con_1' has been established.
# -- Connecting (2)... # -- Connecting (2)...
# -- Establishing connection 'con_2' (user: mysqltest_u1)...
# -- Connection 'con_2' has been established.
# -- Connecting (3)... # -- Connecting (3)...
# -- Connecting (4)... # -- Establishing connection 'con_3' (user: mysqltest_u1)...
ERROR 08004: Too many connections # -- Connection 'con_3' has been established.
# -- Waiting for the last connection to close... # -- Connecting (4) [should fail]...
# -- Establishing connection 'con_4' (user: mysqltest_u1)...
# -- Error: can not establish connection 'con_4'.
# -- Check that we allow one extra SUPER-user connection. # -- Check that we allow one extra SUPER-user connection.
# -- Connecting super (1)... # -- Connecting super (1)...
# -- Connecting super (2)... # -- Establishing connection 'con_super_1' (user: root)...
ERROR HY000: Too many connections # -- Connection 'con_super_1' has been established.
# -- Connecting super (2) [should fail]...
# -- Establishing connection 'con_super_2' (user: root)...
# -- Error: can not establish connection 'con_super_2'.
# -- Ensure that we have Event Scheduler thread, 3 ordinary user
# -- connections and one extra super-user connection.
SELECT user FROM information_schema.processlist ORDER BY id; SELECT user FROM information_schema.processlist ORDER BY id;
user user
event_scheduler event_scheduler
...@@ -165,6 +175,7 @@ SET GLOBAL max_connections = 151; ...@@ -165,6 +175,7 @@ SET GLOBAL max_connections = 151;
# -- Stopping Event Scheduler... # -- Stopping Event Scheduler...
SET GLOBAL event_scheduler = OFF; SET GLOBAL event_scheduler = OFF;
# -- Waiting for Event Scheduler to stop... # -- Waiting for Event Scheduler to stop...
# -- That's it. Closing connections... # -- That's it. Closing connections...
......
...@@ -114,106 +114,94 @@ drop table t1; ...@@ -114,106 +114,94 @@ drop table t1;
--echo # -- End of 4.1 tests --echo # -- End of 4.1 tests
--echo # ------------------------------------------------------------------ --echo # ------------------------------------------------------------------
###########################################################################
--echo --echo
--echo # -- Bug#33507: Event scheduler creates more threads than max_connections --echo # -- Bug#33507: Event scheduler creates more threads than max_connections
--echo # -- which results in user lockout. --echo # -- which results in user lockout.
--echo
--echo
GRANT USAGE ON *.* TO mysqltest_u1@localhost; GRANT USAGE ON *.* TO mysqltest_u1@localhost;
# NOTE: if the test case fails sporadically due to spurious connections, # NOTE: if the test case fails sporadically due to spurious connections,
# consider disabling all users. # consider disabling all users.
--echo --echo
let $saved_max_connections = `SELECT @@global.max_connections`; let $saved_max_connections = `SELECT @@global.max_connections`;
SET GLOBAL max_connections = 3; SET GLOBAL max_connections = 3;
SET GLOBAL event_scheduler = ON; SET GLOBAL event_scheduler = ON;
--echo --echo
--echo # -- Waiting for old connections to close... --echo # -- Waiting for Event Scheduler to start...
let $wait_condition =
SELECT COUNT(*) = 1
FROM information_schema.processlist
WHERE db = 'test';
--source include/wait_condition.inc
--echo
let $wait_condition = let $wait_condition =
SELECT COUNT(*) = 1 SELECT COUNT(*) = 1
FROM information_schema.processlist FROM information_schema.processlist
WHERE user = 'event_scheduler'; WHERE user = 'event_scheduler';
--source include/wait_condition.inc --source include/wait_condition.inc
--echo
--echo
--echo # -- Disconnecting default connection... --echo # -- Disconnecting default connection...
--disconnect default --disconnect default
--echo --echo
--echo # -- Check that we allow exactly three user connections, no matter how --echo # -- Check that we allow exactly three user connections, no matter how
--echo # -- many threads are running. --echo # -- many threads are running.
--echo
--echo
--echo # -- Connecting (1)... --echo # -- Connecting (1)...
--connect (con_1,localhost,mysqltest_u1) let $con_name = con_1;
let $con_user_name = mysqltest_u1;
--source include/connect2.inc
--echo --echo
--echo # -- Waiting for root connection to close...
let $wait_condition =
SELECT COUNT(*) = 1
FROM information_schema.processlist
WHERE db = 'test';
--source include/wait_condition.inc
--echo
--echo # -- Connecting (2)... --echo # -- Connecting (2)...
--connect (con_2,localhost,mysqltest_u1) let $con_name = con_2;
let $con_user_name = mysqltest_u1;
--source include/connect2.inc
--echo
--echo # -- Connecting (3)... --echo # -- Connecting (3)...
--connect (con_3,localhost,mysqltest_u1) let $con_name = con_3;
let $con_user_name = mysqltest_u1;
--echo # -- Connecting (4)... --source include/connect2.inc
--disable_query_log
--error ER_CON_COUNT_ERROR
--connect (con_4,localhost,mysqltest_u1)
--enable_query_log
--echo --echo
--echo # -- Waiting for the last connection to close... --echo # -- Connecting (4) [should fail]...
let $wait_condition = let $con_name = con_4;
SELECT COUNT(*) = 3 let $con_user_name = mysqltest_u1;
FROM information_schema.processlist let $wait_timeout = 5;
WHERE db = 'test'; --source include/connect2.inc
--source include/wait_condition.inc
--echo --echo
--echo # -- Check that we allow one extra SUPER-user connection. --echo # -- Check that we allow one extra SUPER-user connection.
--echo
--echo
--echo # -- Connecting super (1)... --echo # -- Connecting super (1)...
--connect (con_super_1,localhost,root) let $con_name = con_super_1;
let $con_user_name = root;
--source include/connect2.inc
--echo # -- Connecting super (2)... --echo
--disable_query_log --echo # -- Connecting super (2) [should fail]...
--error ER_CON_COUNT_ERROR let $con_name = con_super_2;
--connect (con_super_2,localhost,root) let $con_user_name = root;
--enable_query_log let $wait_timeout = 5;
--source include/connect2.inc
--echo --echo
# Ensure that we have Event Scheduler thread, 3 ordinary user connections and --echo # -- Ensure that we have Event Scheduler thread, 3 ordinary user
# one extra super-user connection. --echo # -- connections and one extra super-user connection.
SELECT user FROM information_schema.processlist ORDER BY id; SELECT user FROM information_schema.processlist ORDER BY id;
--echo --echo
--echo # -- Resetting variables... --echo # -- Resetting variables...
--eval SET GLOBAL max_connections = $saved_max_connections --eval SET GLOBAL max_connections = $saved_max_connections
--echo --echo
--echo # -- Stopping Event Scheduler... --echo # -- Stopping Event Scheduler...
SET GLOBAL event_scheduler = OFF; SET GLOBAL event_scheduler = OFF;
--echo
--echo # -- Waiting for Event Scheduler to stop... --echo # -- Waiting for Event Scheduler to stop...
let $wait_condition = let $wait_condition =
SELECT COUNT(*) = 0 SELECT COUNT(*) = 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment