Commit 4d6c1573 authored by marko's avatar marko

branches/zip: Make innodb_lock_wait_timeout a settable session variable

(Bug #36285, rb://9).

innodb-index.test, innodb-index.result: Set innodb_lock_wait_timeout as
a session variable instead of relying on the global value.

innodb-index-master.opt: Remove.

innodb-timeout.test: Test that setting the innodb_lock_wait_timeout
works as advertised.

thd_lock_wait_timeout(): New function, to retrieve the lock wait timeout
for a given MySQL client connection (thd), or the global value (thd==NULL).

srv_lock_wait_timeout, innobase_lock_wait_timeout: Remove.

Replace MYSQL_SYSVAR_LONG(lock_wait_timeout)
with MYSQL_THDVAR_ULONG(lock_wait_timeout).  
parent dd5c8747
2008-10-03 The InnoDB Team
* mysql-test/innodb-index.test, mysql-test/innodb-index.result,
mysql-test/innodb-timeout.test, mysql-test/innodb-timeout.result,
srv/srv0srv.c, include/srv0srv.h,
handler/ha_innodb.cc, include/ha_prototypes.h:
Make innodb_lock_wait_timeout a settable session variable.
This fixes MySQL Bug #36285.
2008-09-19 The InnoDB Team
* os/os0proc.c:
......
......@@ -128,8 +128,8 @@ static const long AUTOINC_NO_LOCKING = 2;
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_log_buffer_size,
innobase_additional_mem_pool_size, innobase_file_io_threads,
innobase_lock_wait_timeout, innobase_force_recovery,
innobase_open_files, innobase_autoinc_lock_mode;
innobase_force_recovery, innobase_open_files,
innobase_autoinc_lock_mode;
static long long innobase_buffer_pool_size, innobase_log_file_size;
......@@ -318,6 +318,10 @@ static MYSQL_THDVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
"Use strict mode when evaluating create options.",
NULL, NULL, FALSE);
static MYSQL_THDVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
"Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
static handler *innobase_create_handler(handlerton *hton,
TABLE_SHARE *table,
......@@ -674,6 +678,21 @@ thd_is_strict(
return(THDVAR((THD*) thd, strict_mode));
}
/**********************************************************************
Returns the lock wait timeout for the current connection. */
extern "C" UNIV_INTERN
ulong
thd_lock_wait_timeout(
/*==================*/
/* out: the lock wait timeout, in seconds */
void* thd) /* in: thread handle (THD*), or NULL to query
the global innodb_lock_wait_timeout */
{
/* According to <mysql/plugin.h>, passing thd == NULL
returns the global value of the session variable. */
return(THDVAR((THD*) thd, lock_wait_timeout));
}
/************************************************************************
Obtain the InnoDB transaction of a MySQL thread. */
inline
......@@ -1936,7 +1955,6 @@ innobase_init(
srv_n_file_io_threads = (ulint) innobase_file_io_threads;
srv_lock_wait_timeout = (ulint) innobase_lock_wait_timeout;
srv_force_recovery = (ulint) innobase_force_recovery;
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
......@@ -9361,11 +9379,6 @@ static MYSQL_SYSVAR_LONG(force_recovery, innobase_force_recovery,
"Helps to save your data in case the disk image of the database becomes corrupt.",
NULL, NULL, 0, 0, 6, 0);
static MYSQL_SYSVAR_LONG(lock_wait_timeout, innobase_lock_wait_timeout,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back.",
NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The size of the buffer which InnoDB uses to write log to the log files on disk.",
......
......@@ -215,5 +215,15 @@ thd_is_strict(
/* out: true if thd is in strict mode */
void* thd); /* in: thread handle (THD*) */
/**********************************************************************
Returns the lock wait timeout for the current connection. */
ulong
thd_lock_wait_timeout(
/*==================*/
/* out: the lock wait timeout, in seconds */
void* thd); /* in: thread handle (THD*), or NULL to query
the global innodb_lock_wait_timeout */
#endif
#endif
......@@ -107,8 +107,6 @@ extern ibool srv_archive_recovery;
extern dulint srv_archive_recovery_limit_lsn;
#endif /* UNIV_LOG_ARCHIVE */
extern ulint srv_lock_wait_timeout;
extern char* srv_file_flush_method_str;
extern ulint srv_unix_file_flush_method;
extern ulint srv_win_file_flush_method;
......
......@@ -847,10 +847,12 @@ create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb;
insert into t2 select a,left(b,255) from t1;
drop table t1;
rename table t2 to t1;
set innodb_lock_wait_timeout=1;
begin;
select a from t1 limit 1 for update;
a
22
set innodb_lock_wait_timeout=1;
create index t1ba on t1 (b,a);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
commit;
......
......@@ -304,10 +304,12 @@ rename table t2 to t1;
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
set innodb_lock_wait_timeout=1;
begin;
# Obtain an IX lock on the table
select a from t1 limit 1 for update;
connection b;
set innodb_lock_wait_timeout=1;
# This would require an S lock on the table, conflicting with the IX lock.
--error ER_LOCK_WAIT_TIMEOUT
create index t1ba on t1 (b,a);
......
set global innodb_lock_wait_timeout=42;
select @@innodb_lock_wait_timeout;
@@innodb_lock_wait_timeout
42
set innodb_lock_wait_timeout=1;
select @@innodb_lock_wait_timeout;
@@innodb_lock_wait_timeout
1
select @@innodb_lock_wait_timeout;
@@innodb_lock_wait_timeout
42
set global innodb_lock_wait_timeout=347;
select @@innodb_lock_wait_timeout;
@@innodb_lock_wait_timeout
42
set innodb_lock_wait_timeout=1;
select @@innodb_lock_wait_timeout;
@@innodb_lock_wait_timeout
1
select @@innodb_lock_wait_timeout;
@@innodb_lock_wait_timeout
347
create table t1(a int primary key)engine=innodb;
begin;
insert into t1 values(1),(2),(3);
select * from t1 for update;
commit;
a
1
2
3
begin;
insert into t1 values(4);
select * from t1 for update;
commit;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
drop table t1;
set global innodb_lock_wait_timeout=50;
-- source include/have_innodb.inc
let $timeout=`select @@innodb_lock_wait_timeout`;
set global innodb_lock_wait_timeout=42;
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
select @@innodb_lock_wait_timeout;
set innodb_lock_wait_timeout=1;
select @@innodb_lock_wait_timeout;
connection b;
select @@innodb_lock_wait_timeout;
set global innodb_lock_wait_timeout=347;
select @@innodb_lock_wait_timeout;
set innodb_lock_wait_timeout=1;
select @@innodb_lock_wait_timeout;
connect (c,localhost,root,,);
connection c;
select @@innodb_lock_wait_timeout;
connection default;
disconnect c;
connection a;
create table t1(a int primary key)engine=innodb;
begin;
insert into t1 values(1),(2),(3);
connection b;
--send
select * from t1 for update;
connection a;
commit;
connection b;
reap;
connection a;
begin;
insert into t1 values(4);
connection b;
--send
select * from t1 for update;
connection a;
sleep 2;
commit;
connection b;
--error ER_LOCK_WAIT_TIMEOUT
reap;
drop table t1;
connection default;
disconnect a;
disconnect b;
eval set global innodb_lock_wait_timeout=$timeout;
......@@ -154,8 +154,6 @@ UNIV_INTERN ibool srv_archive_recovery = 0;
UNIV_INTERN ib_uint64_t srv_archive_recovery_limit_lsn;
#endif /* UNIV_LOG_ARCHIVE */
UNIV_INTERN ulint srv_lock_wait_timeout = 1024 * 1024 * 1024;
/* This parameter is used to throttle the number of insert buffers that are
merged in a batch. By increasing this parameter on a faster disk you can
possibly reduce the number of I/O operations performed to complete the
......@@ -1377,6 +1375,7 @@ srv_suspend_mysql_thread(
ulint diff_time;
ulint sec;
ulint ms;
ulong lock_wait_timeout;
ut_ad(!mutex_own(&kernel_mutex));
......@@ -1515,8 +1514,14 @@ srv_suspend_mysql_thread(
mutex_exit(&kernel_mutex);
if (srv_lock_wait_timeout < 100000000
&& wait_time > (double)srv_lock_wait_timeout) {
/* InnoDB system transactions (such as the purge, and
incomplete transactions that are being rolled back after crash
recovery) will use the global value of
innodb_lock_wait_timeout, because trx->mysql_thd == NULL. */
lock_wait_timeout = thd_lock_wait_timeout(trx->mysql_thd);
if (lock_wait_timeout < 100000000
&& wait_time > (double) lock_wait_timeout) {
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
}
......@@ -1966,12 +1971,19 @@ srv_lock_timeout_and_monitor_thread(
slot = srv_mysql_table + i;
if (slot->in_use) {
trx_t* trx;
ulong lock_wait_timeout;
some_waits = TRUE;
wait_time = ut_difftime(ut_time(), slot->suspend_time);
if (srv_lock_wait_timeout < 100000000
&& (wait_time > (double) srv_lock_wait_timeout
trx = thr_get_trx(slot->thr);
lock_wait_timeout = thd_lock_wait_timeout(
trx->mysql_thd);
if (lock_wait_timeout < 100000000
&& (wait_time > (double) lock_wait_timeout
|| wait_time < 0)) {
/* Timeout exceeded or a wrap-around in system
......@@ -1981,10 +1993,9 @@ srv_lock_timeout_and_monitor_thread(
possible that the lock has already been
granted: in that case do nothing */
if (thr_get_trx(slot->thr)->wait_lock) {
if (trx->wait_lock) {
lock_cancel_waiting_and_release(
thr_get_trx(slot->thr)
->wait_lock);
trx->wait_lock);
}
}
}
......
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