Skip to content

Commit

Permalink
MDEV-11418 - AliSQL: [Feature] Issue#1 KILL IDLE TRANSACTIONS
Browse files Browse the repository at this point in the history
Terminate idle transactions safely in server layer by setting up socket timeout
parameter. Percona provides another patch to resolve similar problem, but it
calls server layer's callback in InnoDB plugin to close THD, which crashes in
some testcases. See https://bugs.launchpad.net/percona-server/+bug/901060 for
more detailed information.

  1. export parameter trx_idle_timeout to handle all kinds of transactions, the priority is highest
  2. export parameter trx_readonly_idle_timeout to handle read-only transactions
  3. export parameter trx_changes_idle_timeout to handle read-write transactions
  • Loading branch information
Sergey Vojtovich committed Mar 22, 2017
1 parent 8026cd6 commit af22a70
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 5 deletions.
1 change: 0 additions & 1 deletion include/thread_pool_priv.h
Expand Up @@ -58,7 +58,6 @@ int thd_connection_has_data(THD *thd);
void thd_set_net_read_write(THD *thd, uint val);
uint thd_get_net_read_write(THD *thd);
void thd_set_mysys_var(THD *thd, st_my_thread_var *mysys_var);
ulong thd_get_net_wait_timeout(THD *thd);
my_socket thd_get_fd(THD *thd);
int thd_store_globals(THD* thd);

Expand Down
12 changes: 12 additions & 0 deletions mysql-test/r/mysqld--help.result
Expand Up @@ -271,6 +271,15 @@ The following options may be given as the first argument:
height-balanced.
--host-cache-size=# How many host names should be cached to avoid resolving.
(Automatically configured unless set explicitly)
--idle-readonly-transaction-timeout=#
The number of seconds the server waits for read-only idle
transaction
--idle-readwrite-transaction-timeout=#
The number of seconds the server waits for read-write
idle transaction
--idle-transaction-timeout=#
The number of seconds the server waits for idle
transaction
--ignore-builtin-innodb
Disable initialization of builtin InnoDB plugin
--ignore-db-dirs=name
Expand Down Expand Up @@ -1259,6 +1268,9 @@ help TRUE
histogram-size 0
histogram-type SINGLE_PREC_HB
host-cache-size 279
idle-readonly-transaction-timeout 0
idle-readwrite-transaction-timeout 0
idle-transaction-timeout 0
ignore-builtin-innodb FALSE
ignore-db-dirs
init-connect
Expand Down
51 changes: 51 additions & 0 deletions mysql-test/r/transaction_timeout.result
@@ -0,0 +1,51 @@
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
# Test idle_transaction_timeout
connect c0,localhost,root,,test,,;
SHOW VARIABLES LIKE 'idle_%transaction_timeout';
Variable_name Value
idle_readonly_transaction_timeout 0
idle_readwrite_transaction_timeout 0
idle_transaction_timeout 0
SET autocommit=0;
SET idle_transaction_timeout=1;
BEGIN;
SELECT * FROM t1;
a
SELECT * FROM t1;
Got one of the listed errors
disconnect c0;
# Test idle_readonly_transaction_timeout
connect c1,localhost,root,,test,,;
SHOW VARIABLES LIKE 'idle_%transaction_timeout';
Variable_name Value
idle_readonly_transaction_timeout 0
idle_readwrite_transaction_timeout 0
idle_transaction_timeout 0
SET autocommit=0;
SET idle_readonly_transaction_timeout=1;
BEGIN;
SELECT * FROM t1;
a
SELECT * FROM t1;
Got one of the listed errors
disconnect c1;
# Test idle_readwrite_transaction_timeout
connect c2,localhost,root,,test,,;
SHOW VARIABLES LIKE 'idle_%transaction_timeout';
Variable_name Value
idle_readonly_transaction_timeout 0
idle_readwrite_transaction_timeout 0
idle_transaction_timeout 0
SET autocommit=0;
SET idle_readwrite_transaction_timeout=1;
BEGIN;
SELECT * FROM t1;
a
SELECT * FROM t1;
a
INSERT INTO t1 VALUES (1);
SELECT * FROM t1;
Got one of the listed errors
disconnect c2;
connection default;
DROP TABLE t1;
42 changes: 42 additions & 0 deletions mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
Expand Up @@ -1213,6 +1213,48 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME IDLE_READONLY_TRANSACTION_TIMEOUT
SESSION_VALUE 0
GLOBAL_VALUE 0
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of seconds the server waits for read-only idle transaction
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME IDLE_READWRITE_TRANSACTION_TIMEOUT
SESSION_VALUE 0
GLOBAL_VALUE 0
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of seconds the server waits for read-write idle transaction
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME IDLE_TRANSACTION_TIMEOUT
SESSION_VALUE 0
GLOBAL_VALUE 0
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of seconds the server waits for idle transaction
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME IGNORE_BUILTIN_INNODB
SESSION_VALUE NULL
GLOBAL_VALUE OFF
Expand Down
42 changes: 42 additions & 0 deletions mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
Expand Up @@ -1325,6 +1325,48 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME IDLE_READONLY_TRANSACTION_TIMEOUT
SESSION_VALUE 0
GLOBAL_VALUE 0
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of seconds the server waits for read-only idle transaction
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME IDLE_READWRITE_TRANSACTION_TIMEOUT
SESSION_VALUE 0
GLOBAL_VALUE 0
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of seconds the server waits for read-write idle transaction
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME IDLE_TRANSACTION_TIMEOUT
SESSION_VALUE 0
GLOBAL_VALUE 0
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 0
VARIABLE_SCOPE SESSION
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of seconds the server waits for idle transaction
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 31536000
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME IGNORE_BUILTIN_INNODB
SESSION_VALUE NULL
GLOBAL_VALUE OFF
Expand Down
54 changes: 54 additions & 0 deletions mysql-test/t/transaction_timeout.test
@@ -0,0 +1,54 @@
--source include/no_protocol.inc
--source include/have_innodb.inc
--source include/not_embedded.inc

CREATE TABLE t1 (a INT) ENGINE=InnoDB;

--echo # Test idle_transaction_timeout
connect (c0,localhost,root,,test,,);
SHOW VARIABLES LIKE 'idle_%transaction_timeout';
SET autocommit=0;
SET idle_transaction_timeout=1;

BEGIN;
SELECT * FROM t1;
sleep 2;

--error 2006,2013
SELECT * FROM t1;
disconnect c0;

--echo # Test idle_readonly_transaction_timeout
connect (c1,localhost,root,,test,,);
SHOW VARIABLES LIKE 'idle_%transaction_timeout';
SET autocommit=0;
SET idle_readonly_transaction_timeout=1;

BEGIN;
SELECT * FROM t1;
sleep 2;

--error 2006,2013 # Gone away
SELECT * FROM t1;
disconnect c1;

--echo # Test idle_readwrite_transaction_timeout
connect (c2,localhost,root,,test,,);
SHOW VARIABLES LIKE 'idle_%transaction_timeout';
SET autocommit=0;
SET idle_readwrite_transaction_timeout=1;

BEGIN;
SELECT * FROM t1;
sleep 2;

SELECT * FROM t1;
INSERT INTO t1 VALUES (1);
sleep 2;

--error 2006, 2013 # Gone away
SELECT * FROM t1;
disconnect c2;

connection default;
DROP TABLE t1;
12 changes: 11 additions & 1 deletion sql/handler.h
Expand Up @@ -1476,7 +1476,7 @@ struct THD_TRANS
bool trans_did_wait() const {
return (m_unsafe_rollback_flags & DID_WAIT) != 0;
}

bool is_trx_read_write() const;
};


Expand Down Expand Up @@ -1576,6 +1576,16 @@ class Ha_trx_info
};


inline bool THD_TRANS::is_trx_read_write() const
{
Ha_trx_info *ha_info;
for (ha_info= ha_list; ha_info; ha_info= ha_info->next())
if (ha_info->is_trx_read_write())
return TRUE;
return FALSE;
}


enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
ISO_REPEATABLE_READ, ISO_SERIALIZABLE};

Expand Down
27 changes: 27 additions & 0 deletions sql/sql_class.h
Expand Up @@ -695,6 +695,10 @@ typedef struct system_variables
my_bool session_track_state_change;

ulong threadpool_priority;

uint idle_transaction_timeout;
uint idle_readonly_transaction_timeout;
uint idle_readwrite_transaction_timeout;
} SV;

/**
Expand Down Expand Up @@ -4287,6 +4291,29 @@ class THD :public Statement,
current_linfo= 0;
mysql_mutex_unlock(&LOCK_thread_count);
}


uint get_net_wait_timeout()
{
if (in_active_multi_stmt_transaction())
{
if (transaction.all.is_trx_read_write())
{
if (variables.idle_readwrite_transaction_timeout > 0)
return variables.idle_readwrite_transaction_timeout;
}
else
{
if (variables.idle_readonly_transaction_timeout > 0)
return variables.idle_readonly_transaction_timeout;
}

if (variables.idle_transaction_timeout > 0)
return variables.idle_transaction_timeout;
}

return variables.net_wait_timeout;
}
};

inline void add_to_active_threads(THD *thd)
Expand Down
4 changes: 2 additions & 2 deletions sql/sql_parse.cc
Expand Up @@ -1210,8 +1210,8 @@ bool do_command(THD *thd)
the client, the connection is closed or "net_wait_timeout"
number of seconds has passed.
*/
if(!thd->skip_wait_timeout)
my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
if (!thd->skip_wait_timeout)
my_net_set_read_timeout(net, thd->get_net_wait_timeout());

/*
XXX: this code is here only to clear possible errors of init_connect.
Expand Down
21 changes: 21 additions & 0 deletions sql/sys_vars.cc
Expand Up @@ -3519,6 +3519,27 @@ static Sys_var_ulong Sys_net_wait_timeout(
VALID_RANGE(1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)),
DEFAULT(NET_WAIT_TIMEOUT), BLOCK_SIZE(1));

static Sys_var_uint Sys_idle_transaction_timeout(
"idle_transaction_timeout",
"The number of seconds the server waits for idle transaction",
SESSION_VAR(idle_transaction_timeout), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)),
DEFAULT(0), BLOCK_SIZE(1));

static Sys_var_uint Sys_idle_readonly_transaction_timeout(
"idle_readonly_transaction_timeout",
"The number of seconds the server waits for read-only idle transaction",
SESSION_VAR(idle_readonly_transaction_timeout), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)),
DEFAULT(0), BLOCK_SIZE(1));

static Sys_var_uint Sys_idle_readwrite_transaction_timeout(
"idle_readwrite_transaction_timeout",
"The number of seconds the server waits for read-write idle transaction",
SESSION_VAR(idle_readwrite_transaction_timeout), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)),
DEFAULT(0), BLOCK_SIZE(1));

static Sys_var_plugin Sys_default_storage_engine(
"default_storage_engine", "The default storage engine for new tables",
SESSION_VAR(table_plugin), NO_CMD_LINE,
Expand Down
2 changes: 1 addition & 1 deletion sql/threadpool_common.cc
Expand Up @@ -199,7 +199,7 @@ void tp_callback(TP_connection *c)
c->priority= get_priority(c);

/* Read next command from client. */
c->set_io_timeout(thd->variables.net_wait_timeout);
c->set_io_timeout(thd->get_net_wait_timeout());
c->state= TP_STATE_IDLE;
if (c->start_io())
goto error;
Expand Down

0 comments on commit af22a70

Please sign in to comment.