MDEV-11418 - AliSQL: [Feature] Issue#1 KILL IDLE TRANSACTIONS

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
This commit is contained in:
Sergey Vojtovich 2017-02-21 16:28:42 +04:00
parent 8026cd6202
commit af22a70df9
11 changed files with 263 additions and 5 deletions

View File

@ -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);

View File

@ -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
@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
};
@ -1576,6 +1576,16 @@ private:
};
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};

View File

@ -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;
/**
@ -4287,6 +4291,29 @@ public:
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)

View File

@ -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.

View File

@ -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,

View File

@ -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;