Skip to content

Commit

Permalink
WL#12999 Make the client get a better error message on wait_timeout
Browse files Browse the repository at this point in the history
When the server terminates a client connection because of timeout, it
tries to send an error message to the client. This message is later
caught by the client on a best effort as the client discover that
the write socket is terminated.
Patch contributed by Mattias Jonsson @ booking.

RB: 25049
  • Loading branch information
Kristofer Älvring committed Nov 19, 2020
1 parent 42abcc4 commit 14508bb
Show file tree
Hide file tree
Showing 15 changed files with 214 additions and 68 deletions.
25 changes: 20 additions & 5 deletions client/mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3042,11 +3042,19 @@ static int reconnect(void) {
return 0;
}

static void get_current_db() {
/**
Checks the current DB and updates the global variable current_db
If the command fails hen he current_db is set to nullptr.
@return Error state
@retval true An error occurred
@retval false Success; current_db is updated
*/
static bool get_current_db() {
MYSQL_RES *res;

/* If one_database is set, current_db is not supposed to change. */
if (one_database) return;
if (one_database) return false;

my_free(current_db);
current_db = nullptr;
Expand All @@ -3057,7 +3065,11 @@ static void get_current_db() {
if (row && row[0])
current_db = my_strdup(PSI_NOT_INSTRUMENTED, row[0], MYF(MY_WME));
mysql_free_result(res);
} else {
/* We failed to issue the command and we likely lost connection */
return true;
}
return false;
}

/***************************************************************************
Expand All @@ -3073,8 +3085,10 @@ static int mysql_real_query_for_lazy(const char *buf, size_t length,
if (set_params && global_attrs->set_params(&mysql)) break;
if (!mysql_real_query(&mysql, buf, (ulong)length)) break;
error = put_error(&mysql);
if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 ||
!opt_reconnect)
if ((mysql_errno(&mysql) != CR_SERVER_GONE_ERROR &&
mysql_errno(&mysql) != CR_SERVER_LOST &&
mysql.net.error != NET_ERROR_SOCKET_UNUSABLE) ||
retry > 1 || !opt_reconnect)
break;
if (reconnect()) break;
}
Expand Down Expand Up @@ -4270,8 +4284,9 @@ static int com_use(String *buffer MY_ATTRIBUTE((unused)), char *line) {
We need to recheck the current database, because it may change
under our feet, for example if DROP DATABASE or RENAME DATABASE
(latter one not yet available by the time the comment was written)
If this command fails we assume we lost connection.
*/
get_current_db();
if (get_current_db()) connected = false;

if (!current_db || cmp_database(charset_info, current_db, tmp)) {
if (one_database) {
Expand Down
6 changes: 6 additions & 0 deletions include/mysql_com.h
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,12 @@ struct Vio;
/// Default width for blob in bytes @todo - align this with sizes from field.h
#define MAX_BLOB_WIDTH 16777216

#define NET_ERROR_UNSET 0 /**< No error has occurred yet */
#define NET_ERROR_SOCKET_RECOVERABLE 1 /**< Socket still usable */
#define NET_ERROR_SOCKET_UNUSABLE 2 /**< Do not use the socket */
#define NET_ERROR_SOCKET_NOT_READABLE 3 /**< Try write and close socket */
#define NET_ERROR_SOCKET_NOT_WRITABLE 4 /**< Try read and close socket */

typedef struct NET {
MYSQL_VIO vio;
unsigned char *buff, *buff_end, *write_pos, *read_pos;
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/wait_until_connected_again.inc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ while ($mysql_errno)
# Strangely enough, the server might return "Too many connections"
# while being shutdown, thus 1040 is an "allowed" error
# See BUG#36228
--error 0,1040,1053,2002,2003,2006,2013,1045,ER_SECURE_TRANSPORT_REQUIRED,2016,2017
--error 0,1040,1053,2002,2003,2006,2013,1045,ER_SECURE_TRANSPORT_REQUIRED,2016,2017,ER_CLIENT_INTERACTION_TIMEOUT
show session status;
if ($mysql_errno == 1045){
--let mysql_errno=0
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/wait_until_disconnected.inc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if ($disconnect_timeout)
let $mysql_errno= 0;
while (!$mysql_errno)
{
--error 0,1040,1053,2002,2003,2006,2013,2016,2017
--error 0,1040,1053,2002,2003,2006,2013,2016,2017,ER_CLIENT_INTERACTION_TIMEOUT
show session status;

dec $counter;
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/r/mysqltest.result
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,7 @@ SELECT 1 AS res;
res
1
SELECT 1 AS res;
ERROR HY000: MySQL server has gone away
Got one of the listed errors
#
# Bug#23743035: ADD A COPY_FILES_WILDCARD COMMAND
#
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/r/ssl.result
Original file line number Diff line number Diff line change
Expand Up @@ -2275,6 +2275,6 @@ Ssl_cipher SSL_CIPHER
SET @@SESSION.wait_timeout = 2;
# Wait for ssl_con to be disconnected.
# Check that ssl_con has been disconnected.
# CR_SERVER_LOST, CR_SERVER_GONE_ERROR
# Different behavior depending on how the plattform implements the
SELECT 1;
Got one of the listed errors
22 changes: 20 additions & 2 deletions mysql-test/r/wait_timeout.result
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ disconnection con1;
SET @@SESSION.wait_timeout = 2;
# Wait for con1 to be disconnected.
# Check that con1 has been disconnected.
# CR_SERVER_LOST, CR_SERVER_GONE_ERROR
SELECT 1;
Got one of the listed errors
#
Expand All @@ -52,8 +51,27 @@ Got one of the listed errors
SET @@SESSION.wait_timeout = 2;
# Wait for con1 to be disconnected.
# Check that con1 has been disconnected.
# CR_SERVER_LOST, CR_SERVER_GONE_ERROR
# Client interaction timeout
SELECT 1;
Got one of the listed errors
SELECT "Check that we don't reconnect with reconnection disabled.";
Got one of the listed errors
#
# Test UNIX domain sockets timeout with reconnect.
#
# Open con2 and set a timeout.
--enable_reconnect;
SET @is_old_connection = 1;
SELECT @is_old_connection;
@is_old_connection
1
SET @@SESSION.wait_timeout = 2;
# Wait for con2 to be disconnected.
# Check that con2 has been reconnected.
SELECT "Unix domain socket will hit wait_timeout with reconnect";
Got one of the listed errors
SELECT @is_old_connection;
@is_old_connection
NULL
# must find the pattern
Pattern "The wait_timeout period was exceeded, the idle time since last command was too long." found
2 changes: 1 addition & 1 deletion mysql-test/t/mysqltest.test
Original file line number Diff line number Diff line change
Expand Up @@ -3287,7 +3287,7 @@ SELECT 1 AS res;
disconnect con1;
--source include/wait_until_disconnected.inc

--error CR_SERVER_GONE_ERROR
--error CR_SERVER_GONE_ERROR,CR_SERVER_LOST
SELECT 1 AS res;

connection default;
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/t/ssl.test
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ let $wait_condition=

--echo # Check that ssl_con has been disconnected.
connection ssl_con;
--echo # CR_SERVER_LOST, CR_SERVER_GONE_ERROR
--error 2006,2013
--echo # Different behavior depending on how the plattform implements the
--error ER_CLIENT_INTERACTION_TIMEOUT,CR_SERVER_LOST
SELECT 1;

connection default;
Expand Down
49 changes: 40 additions & 9 deletions mysql-test/t/wait_timeout.test
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ connection default;
# When the connection is closed in this way, the error code should
# be consistent see Bug#2845 for an explanation
# depending on platform/client, either errno 2006 or 2013 can occur below
--error 2006,2013
--error ER_CLIENT_INTERACTION_TIMEOUT,CR_SERVER_LOST
SELECT 2;
--echo --enable_reconnect;
--enable_reconnect
Expand Down Expand Up @@ -123,7 +123,7 @@ connection con1;
# When the connection is closed in this way, the error code should
# be consistent see Bug#2845 for an explanation
# depending on platform/client, either errno 2006 or 2013 can occur below
--error 2006,2013
--error ER_CLIENT_INTERACTION_TIMEOUT,CR_SERVER_LOST
SELECT 2;
--echo --enable_reconnect;
--enable_reconnect
Expand All @@ -148,6 +148,7 @@ connect (default,localhost,root,,test,,);
--echo # Open con1 and set a timeout.
connect(con1,localhost,root,,);

--disable_reconnect
LET $ID= `SELECT connection_id()`;
SET @@SESSION.wait_timeout = 2;

Expand All @@ -160,8 +161,7 @@ let $wait_condition=

--echo # Check that con1 has been disconnected.
connection con1;
--echo # CR_SERVER_LOST, CR_SERVER_GONE_ERROR
--error 2006,2013
--error ER_CLIENT_INTERACTION_TIMEOUT,CR_SERVER_LOST
SELECT 1;

disconnect con1;
Expand All @@ -172,7 +172,7 @@ connection default;
--echo #

--echo # Open con1 and set a timeout.
connect(con1,127.0.0.1,root,,);
connect(con1,127.0.0.1,root,,,,,TCP,,);

LET $ID= `SELECT connection_id()`;
SET @@SESSION.wait_timeout = 2;
Expand All @@ -186,16 +186,47 @@ let $wait_condition=

--echo # Check that con1 has been disconnected.
connection con1;
--echo # CR_SERVER_LOST, CR_SERVER_GONE_ERROR
--error 2006,2013
--disable_reconnect
--echo # Client interaction timeout
--error ER_CLIENT_INTERACTION_TIMEOUT,CR_SERVER_LOST
SELECT 1;

disconnect con1;
--error ER_CLIENT_INTERACTION_TIMEOUT,CR_SERVER_LOST
SELECT "Check that we don't reconnect with reconnection disabled.";

--echo #
--echo # Test UNIX domain sockets timeout with reconnect.
--echo #

--echo # Open con2 and set a timeout.
connect(con2,localhost,root,,);

--echo --enable_reconnect;
--enable_reconnect
SET @is_old_connection = 1;
SELECT @is_old_connection;

LET $ID= `SELECT connection_id()`;
SET @@SESSION.wait_timeout = 2;

--echo # Wait for con2 to be disconnected.
connection default;
let $wait_condition=
SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE ID = $ID;
--source include/wait_condition.inc

--echo # Check that con2 has been reconnected.
connection con2;
--error ER_CLIENT_INTERACTION_TIMEOUT,CR_SERVER_LOST
SELECT "Unix domain socket will hit wait_timeout with reconnect";
SELECT @is_old_connection;
connection default;
--disable_reconnect
disconnect con2;
disconnect con1;
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc

#
# Bug #28940167 WAIT_TIMEOUT ERROR NOT CLEAR AND NOT SENT TO CLIENT BEFORE CLOSING CONNECTION
#
Expand Down
3 changes: 3 additions & 0 deletions share/messages_to_clients.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9502,6 +9502,9 @@ ER_TABLE_MUST_HAVE_A_VISIBLE_COLUMN
ER_WARN_IMPORT_COMPRESSION_FAIL
eng "Compression failed while doing import with the following error : %s"

ER_CLIENT_INTERACTION_TIMEOUT
eng "The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior."

#
# End of 8.0 error messages (server-to-client).
# Do NOT add messages intended for the error log above!
Expand Down
Loading

0 comments on commit 14508bb

Please sign in to comment.