Commit 08ce9bfe authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-4566 : Failing DBUG_ASSERT() in SELECT SLEEP(), with threadpool.

This bug only happens with long sleep()s ( > 5 sec), and in debug version.

Analysis: 
The assertion is caused by nested thd_wait_begin() calls, which is not an expected condition.
-  "outer" thd_wait_begin()) , in Item_func_sleep::val_int()
-  "inner" thd_wait_begin() in Interruptible_wait::wait(). This function periodically checks whether connection is still valid, via THD::is_connection(), which ends up  calling vio_io_wait()  with timeout parameter set to  0.


Fix is not to call thd wait callback in vio_io_wait(), if timeout parameter is 0. There is no "waiting" in this case.
parent 52045d40
...@@ -2157,10 +2157,10 @@ Warnings: ...@@ -2157,10 +2157,10 @@ Warnings:
Warning 1052 Column 'kundentyp' in group statement is ambiguous Warning 1052 Column 'kundentyp' in group statement is ambiguous
drop table t1; drop table t1;
SET optimizer_switch=@save_optimizer_switch; SET optimizer_switch=@save_optimizer_switch;
SELECT sleep(5); SELECT sleep(5.5);
SELECT sleep(5); SELECT sleep(5);
# -- Success: more than --thread_pool_max_threads normal connections not possible # -- Success: more than --thread_pool_max_threads normal connections not possible
sleep(5) sleep(5.5)
0 0
sleep(5) sleep(5)
0 0
......
...@@ -17,7 +17,10 @@ SET optimizer_switch=@save_optimizer_switch; ...@@ -17,7 +17,10 @@ SET optimizer_switch=@save_optimizer_switch;
# First set two connections running, and check that extra connection # First set two connections running, and check that extra connection
# on normal port fails due to--thread-pool-max_threads=2 # on normal port fails due to--thread-pool-max_threads=2
connection default; connection default;
send SELECT sleep(5);
# Sleep for slightly longer than 5 sec to trigger MDEV-4566
# (abort in interruptible wait connection check)
send SELECT sleep(5.5);
--sleep 1 --sleep 1
connect(con2,localhost,root,,); connect(con2,localhost,root,,);
......
...@@ -42,21 +42,21 @@ static void (*before_io_wait)(void)= 0; ...@@ -42,21 +42,21 @@ static void (*before_io_wait)(void)= 0;
static void (*after_io_wait)(void)= 0; static void (*after_io_wait)(void)= 0;
/* Wait callback macros (both performance schema and threadpool */ /* Wait callback macros (both performance schema and threadpool */
#define START_SOCKET_WAIT(locker, state_ptr, sock, which) \ #define START_SOCKET_WAIT(locker, state_ptr, sock, which, timeout) \
do \ do \
{ \ { \
MYSQL_START_SOCKET_WAIT(locker, state_ptr, sock, \ MYSQL_START_SOCKET_WAIT(locker, state_ptr, sock, \
which, 0); \ which, 0); \
if (before_io_wait) \ if (timeout && before_io_wait) \
before_io_wait(); \ before_io_wait(); \
} while(0) } while(0)
#define END_SOCKET_WAIT(locker) \ #define END_SOCKET_WAIT(locker,timeout) \
do \ do \
{ \ { \
MYSQL_END_SOCKET_WAIT(locker, 0); \ MYSQL_END_SOCKET_WAIT(locker, 0); \
if (after_io_wait) \ if (timeout && after_io_wait) \
after_io_wait(); \ after_io_wait(); \
} while(0) } while(0)
...@@ -930,11 +930,11 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout) ...@@ -930,11 +930,11 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
if (timeout != 0 && vio->async_context && vio->async_context->active) if (timeout != 0 && vio->async_context && vio->async_context->active)
{ {
START_SOCKET_WAIT(locker, &state, vio->mysql_socket, START_SOCKET_WAIT(locker, &state, vio->mysql_socket,
PSI_SOCKET_SELECT); PSI_SOCKET_SELECT, timeout);
ret= my_io_wait_async(vio->async_context, event, timeout); ret= my_io_wait_async(vio->async_context, event, timeout);
if (ret == 0) if (ret == 0)
errno= SOCKET_ETIMEDOUT; errno= SOCKET_ETIMEDOUT;
END_SOCKET_WAIT(locker); END_SOCKET_WAIT(locker,timeout);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -959,7 +959,7 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout) ...@@ -959,7 +959,7 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
break; break;
} }
START_SOCKET_WAIT(locker, &state, vio->mysql_socket, PSI_SOCKET_SELECT); START_SOCKET_WAIT(locker, &state, vio->mysql_socket, PSI_SOCKET_SELECT, timeout);
/* /*
Wait for the I/O event and return early in case of Wait for the I/O event and return early in case of
error or timeout. error or timeout.
...@@ -982,7 +982,7 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout) ...@@ -982,7 +982,7 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
break; break;
} }
END_SOCKET_WAIT(locker); END_SOCKET_WAIT(locker, timeout);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -1004,11 +1004,11 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout) ...@@ -1004,11 +1004,11 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
if (timeout != 0 && vio->async_context && vio->async_context->active) if (timeout != 0 && vio->async_context && vio->async_context->active)
{ {
START_SOCKET_WAIT(locker, &state, vio->mysql_socket, START_SOCKET_WAIT(locker, &state, vio->mysql_socket,
PSI_SOCKET_SELECT); PSI_SOCKET_SELECT, timeout);
ret= my_io_wait_async(vio->async_context, event, timeout); ret= my_io_wait_async(vio->async_context, event, timeout);
if (ret == 0) if (ret == 0)
WSASetLastError(SOCKET_ETIMEDOUT); WSASetLastError(SOCKET_ETIMEDOUT);
END_SOCKET_WAIT(locker); END_SOCKET_WAIT(locker, timeout);
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -1039,12 +1039,12 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout) ...@@ -1039,12 +1039,12 @@ int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
break; break;
} }
START_SOCKET_WAIT(locker, &state, vio->mysql_socket, PSI_SOCKET_SELECT); START_SOCKET_WAIT(locker, &state, vio->mysql_socket, PSI_SOCKET_SELECT, timeout);
/* The first argument is ignored on Windows. */ /* The first argument is ignored on Windows. */
ret= select(0, &readfds, &writefds, &exceptfds, (timeout >= 0) ? &tm : NULL); ret= select(0, &readfds, &writefds, &exceptfds, (timeout >= 0) ? &tm : NULL);
END_SOCKET_WAIT(locker); END_SOCKET_WAIT(locker, timeout);
/* Set error code to indicate a timeout error. */ /* Set error code to indicate a timeout error. */
if (ret == 0) if (ret == 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