diff options
author | Yasufumi Kinoshita <yasufumi.kinoshita@oracle.com> | 2012-01-10 14:18:58 +0900 |
---|---|---|
committer | Yasufumi Kinoshita <yasufumi.kinoshita@oracle.com> | 2012-01-10 14:18:58 +0900 |
commit | 115f5e8551b9243ef3ca98ce882993fb78c426e1 (patch) | |
tree | eb3e73644289ee45d9adcc3caba490fbd1311178 | |
parent | 13b265483e0aeefdc6de8bd227ca0dfc7cd91736 (diff) | |
download | mariadb-git-115f5e8551b9243ef3ca98ce882993fb78c426e1.tar.gz |
Bug#12400341 INNODB CAN LEAVE ORPHAN IBD FILES AROUND
If we meet DB_TOO_MANY_CONCURRENT_TRXS during the execution tab_create_graph from row_create_table_for_mysql(), .ibd file for the table should be created already but was not deleted for the error handling.
rb:875 approved by Jimmy Yang
-rw-r--r-- | mysql-test/suite/innodb/r/innodb_bug12400341.result | 25 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/innodb_bug12400341-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/innodb_bug12400341.test | 103 | ||||
-rw-r--r-- | mysql-test/suite/innodb_plugin/r/innodb_bug12400341.result | 25 | ||||
-rw-r--r-- | mysql-test/suite/innodb_plugin/t/innodb_bug12400341-master.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/innodb_plugin/t/innodb_bug12400341.test | 103 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 10 | ||||
-rw-r--r-- | storage/innobase/include/trx0rseg.ic | 9 | ||||
-rw-r--r-- | storage/innobase/include/trx0sys.h | 5 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.c | 12 | ||||
-rw-r--r-- | storage/innobase/trx/trx0sys.c | 4 | ||||
-rw-r--r-- | storage/innodb_plugin/ChangeLog | 5 | ||||
-rw-r--r-- | storage/innodb_plugin/handler/ha_innodb.cc | 10 | ||||
-rw-r--r-- | storage/innodb_plugin/include/trx0rseg.ic | 9 | ||||
-rw-r--r-- | storage/innodb_plugin/include/trx0sys.h | 6 | ||||
-rw-r--r-- | storage/innodb_plugin/row/row0mysql.c | 14 | ||||
-rw-r--r-- | storage/innodb_plugin/trx/trx0sys.c | 5 |
17 files changed, 345 insertions, 2 deletions
diff --git a/mysql-test/suite/innodb/r/innodb_bug12400341.result b/mysql-test/suite/innodb/r/innodb_bug12400341.result new file mode 100644 index 00000000000..551e94f5e77 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug12400341.result @@ -0,0 +1,25 @@ +call mtr.add_suppression("InnoDB: Warning: cannot find a free slot for an undo log. Do you have too"); +show variables like "max_connections"; +Variable_name Value +max_connections 64 +show variables like "innodb_thread_concurrency"; +Variable_name Value +innodb_thread_concurrency 0 +show variables like "innodb_file_per_table"; +Variable_name Value +innodb_file_per_table ON +drop database if exists mysqltest; +create database mysqltest; +CREATE TABLE mysqltest.transtable (id int unsigned NOT NULL PRIMARY KEY, val int DEFAULT 0) ENGINE=InnoDB; +select count(*) from information_schema.processlist; +count(*) +33 +CREATE TABLE mysqltest.testtable (id int unsigned not null primary key) ENGINE=InnoDB; +ERROR HY000: Can't create table 'mysqltest.testtable' (errno: 177) +select count(*) from information_schema.processlist; +count(*) +33 +select count(*) from information_schema.processlist; +count(*) +33 +drop database mysqltest; diff --git a/mysql-test/suite/innodb/t/innodb_bug12400341-master.opt b/mysql-test/suite/innodb/t/innodb_bug12400341-master.opt new file mode 100644 index 00000000000..2e85b082c68 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug12400341-master.opt @@ -0,0 +1 @@ +--max_connections=64 --innodb_thread_concurrency=0 --innodb_file_per_table diff --git a/mysql-test/suite/innodb/t/innodb_bug12400341.test b/mysql-test/suite/innodb/t/innodb_bug12400341.test new file mode 100644 index 00000000000..2ab1be81f6d --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug12400341.test @@ -0,0 +1,103 @@ +# Test for bug #12400341: INNODB CAN LEAVE ORPHAN IBD FILES AROUND + +-- source include/have_innodb.inc + +if (`select count(*)=0 from information_schema.global_variables where variable_name = 'INNODB_TRX_RSEG_N_SLOTS_DEBUG'`) +{ + --skip Test requires InnoDB built with UNIV_DEBUG definition. +} + +call mtr.add_suppression("InnoDB: Warning: cannot find a free slot for an undo log. Do you have too"); + +--disable_query_log +set @old_innodb_trx_rseg_n_slots_debug = @@innodb_trx_rseg_n_slots_debug; +set global innodb_trx_rseg_n_slots_debug = 32; +--enable_query_log + +show variables like "max_connections"; +show variables like "innodb_thread_concurrency"; +show variables like "innodb_file_per_table"; + +--disable_warnings +drop database if exists mysqltest; +--enable_warnings + +create database mysqltest; +CREATE TABLE mysqltest.transtable (id int unsigned NOT NULL PRIMARY KEY, val int DEFAULT 0) ENGINE=InnoDB; + +--disable_query_log +# +# Insert in 1 transaction which needs over 1 page undo record to avoid the insert_undo cached, +# because the cached insert_undo can be reused at "CREATE TABLE" statement later. +# +START TRANSACTION; +let $c = 1024; +while ($c) +{ + eval INSERT INTO mysqltest.transtable (id) VALUES ($c); + dec $c; +} +COMMIT; + +let $c = 32; +while ($c) +{ + # if failed at here, it might be shortage of file descriptors limit. + connect (con$c,localhost,root,,); + dec $c; +} +--enable_query_log + +select count(*) from information_schema.processlist; + +# +# fill the all undo slots +# +--disable_query_log +let $c = 32; +while ($c) +{ + connection con$c; + START TRANSACTION; + eval UPDATE mysqltest.transtable SET val = 1 WHERE id = 33 - $c; + dec $c; +} +--enable_query_log + +connection default; + +--error ER_CANT_CREATE_TABLE +CREATE TABLE mysqltest.testtable (id int unsigned not null primary key) ENGINE=InnoDB; + +select count(*) from information_schema.processlist; + +--disable_query_log +let $c = 32; +while ($c) +{ + connection con$c; + ROLLBACK; + dec $c; +} +--enable_query_log + +connection default; +select count(*) from information_schema.processlist; + +--disable_query_log +let $c = 32; +while ($c) +{ + disconnect con$c; + dec $c; +} +--enable_query_log + +# +# If the isolated .ibd file remained, the drop database should fail. +# +drop database mysqltest; + +--disable_query_log +set global innodb_trx_rseg_n_slots_debug = @old_innodb_trx_rseg_n_slots_debug; +--enable_query_log diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug12400341.result b/mysql-test/suite/innodb_plugin/r/innodb_bug12400341.result new file mode 100644 index 00000000000..551e94f5e77 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug12400341.result @@ -0,0 +1,25 @@ +call mtr.add_suppression("InnoDB: Warning: cannot find a free slot for an undo log. Do you have too"); +show variables like "max_connections"; +Variable_name Value +max_connections 64 +show variables like "innodb_thread_concurrency"; +Variable_name Value +innodb_thread_concurrency 0 +show variables like "innodb_file_per_table"; +Variable_name Value +innodb_file_per_table ON +drop database if exists mysqltest; +create database mysqltest; +CREATE TABLE mysqltest.transtable (id int unsigned NOT NULL PRIMARY KEY, val int DEFAULT 0) ENGINE=InnoDB; +select count(*) from information_schema.processlist; +count(*) +33 +CREATE TABLE mysqltest.testtable (id int unsigned not null primary key) ENGINE=InnoDB; +ERROR HY000: Can't create table 'mysqltest.testtable' (errno: 177) +select count(*) from information_schema.processlist; +count(*) +33 +select count(*) from information_schema.processlist; +count(*) +33 +drop database mysqltest; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug12400341-master.opt b/mysql-test/suite/innodb_plugin/t/innodb_bug12400341-master.opt new file mode 100644 index 00000000000..2e85b082c68 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug12400341-master.opt @@ -0,0 +1 @@ +--max_connections=64 --innodb_thread_concurrency=0 --innodb_file_per_table diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug12400341.test b/mysql-test/suite/innodb_plugin/t/innodb_bug12400341.test new file mode 100644 index 00000000000..b9e40e0dff3 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug12400341.test @@ -0,0 +1,103 @@ +# Test for bug #12400341: INNODB CAN LEAVE ORPHAN IBD FILES AROUND + +-- source include/have_innodb_plugin.inc + +if (`select count(*)=0 from information_schema.global_variables where variable_name = 'INNODB_TRX_RSEG_N_SLOTS_DEBUG'`) +{ + --skip Test requires InnoDB built with UNIV_DEBUG definition. +} + +call mtr.add_suppression("InnoDB: Warning: cannot find a free slot for an undo log. Do you have too"); + +--disable_query_log +set @old_innodb_trx_rseg_n_slots_debug = @@innodb_trx_rseg_n_slots_debug; +set global innodb_trx_rseg_n_slots_debug = 32; +--enable_query_log + +show variables like "max_connections"; +show variables like "innodb_thread_concurrency"; +show variables like "innodb_file_per_table"; + +--disable_warnings +drop database if exists mysqltest; +--enable_warnings + +create database mysqltest; +CREATE TABLE mysqltest.transtable (id int unsigned NOT NULL PRIMARY KEY, val int DEFAULT 0) ENGINE=InnoDB; + +--disable_query_log +# +# Insert in 1 transaction which needs over 1 page undo record to avoid the insert_undo cached, +# because the cached insert_undo can be reused at "CREATE TABLE" statement later. +# +START TRANSACTION; +let $c = 1024; +while ($c) +{ + eval INSERT INTO mysqltest.transtable (id) VALUES ($c); + dec $c; +} +COMMIT; + +let $c = 32; +while ($c) +{ + # if failed at here, it might be shortage of file descriptors limit. + connect (con$c,localhost,root,,); + dec $c; +} +--enable_query_log + +select count(*) from information_schema.processlist; + +# +# fill the all undo slots +# +--disable_query_log +let $c = 32; +while ($c) +{ + connection con$c; + START TRANSACTION; + eval UPDATE mysqltest.transtable SET val = 1 WHERE id = 33 - $c; + dec $c; +} +--enable_query_log + +connection default; + +--error ER_CANT_CREATE_TABLE +CREATE TABLE mysqltest.testtable (id int unsigned not null primary key) ENGINE=InnoDB; + +select count(*) from information_schema.processlist; + +--disable_query_log +let $c = 32; +while ($c) +{ + connection con$c; + ROLLBACK; + dec $c; +} +--enable_query_log + +connection default; +select count(*) from information_schema.processlist; + +--disable_query_log +let $c = 32; +while ($c) +{ + disconnect con$c; + dec $c; +} +--enable_query_log + +# +# If the isolated .ibd file remained, the drop database should fail. +# +drop database mysqltest; + +--disable_query_log +set global innodb_trx_rseg_n_slots_debug = @old_innodb_trx_rseg_n_slots_debug; +--enable_query_log diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a4d79a5934e..573e0a4455a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9060,6 +9060,13 @@ static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug, NULL, NULL, 0, 0, 1, 0); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef UNIV_DEBUG +static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug, + PLUGIN_VAR_RQCMDARG, + "Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()", + NULL, NULL, 0, 0, 1024, 0); +#endif /* UNIV_DEBUG */ + static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(autoextend_increment), @@ -9105,6 +9112,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG MYSQL_SYSVAR(change_buffering_debug), #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ +#ifdef UNIV_DEBUG + MYSQL_SYSVAR(trx_rseg_n_slots_debug), +#endif /* UNIV_DEBUG */ NULL }; diff --git a/storage/innobase/include/trx0rseg.ic b/storage/innobase/include/trx0rseg.ic index 577cd0dee7b..5b01b2f197d 100644 --- a/storage/innobase/include/trx0rseg.ic +++ b/storage/innobase/include/trx0rseg.ic @@ -8,6 +8,7 @@ Created 3/26/1996 Heikki Tuuri #include "srv0srv.h" #include "mtr0log.h" +#include "trx0sys.h" /********************************************************************** Gets a rollback segment header. */ @@ -113,7 +114,13 @@ trx_rsegf_undo_find_free( ulint i; ulint page_no; - for (i = 0; i < TRX_RSEG_N_SLOTS; i++) { + for (i = 0; +#ifndef UNIV_DEBUG + i < TRX_RSEG_N_SLOTS; +#else + i < (trx_rseg_n_slots_debug ? trx_rseg_n_slots_debug : TRX_RSEG_N_SLOTS); +#endif + i++) { page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr); diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 7ea981eb85c..aedeb51d3b3 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -47,6 +47,11 @@ extern ibool trx_doublewrite_buf_is_being_created; extern ibool trx_doublewrite_must_reset_space_ids; extern ibool trx_sys_multiple_tablespace_format; +#ifdef UNIV_DEBUG +/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ +extern uint trx_rseg_n_slots_debug; +#endif + /******************************************************************** Creates the doublewrite buffer to a new InnoDB installation. The header of the doublewrite buffer is placed on the trx system header page. */ diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index cee97871470..6148b01af9d 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1948,6 +1948,18 @@ row_create_table_for_mysql( FALSE); } + } else if (err == DB_TOO_MANY_CONCURRENT_TRXS) { + /* We already have .ibd file here. it should be deleted. */ + if (table->space + && !fil_delete_tablespace(table->space)) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: not able to" + " delete tablespace %lu of table ", + (ulong) table->space); + ut_print_name(stderr, trx, TRUE, table->name); + fputs("!\n", stderr); + } } else if (err == DB_DUPLICATE_KEY) { ut_print_timestamp(stderr); diff --git a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c index 137771b71ed..09b1b5d8198 100644 --- a/storage/innobase/trx/trx0sys.c +++ b/storage/innobase/trx/trx0sys.c @@ -54,6 +54,10 @@ InnoDB. */ char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN]; ib_longlong trx_sys_mysql_bin_log_pos = -1; +#ifdef UNIV_DEBUG +/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ +uint trx_rseg_n_slots_debug = 0; +#endif /******************************************************************** Determines if a page number is located inside the doublewrite buffer. */ diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 1385da94bfb..d33dfd33043 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2012-01-04 The InnoDB Team + + * row/row0mysql.c: + Fix Bug#12400341: INNODB CAN LEAVE ORPHAN IBD FILES AROUND + 2011-12-21 The InnoDB Team * include/ut0rnd.ic: diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 122bf1f7846..149e660e36e 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -11033,6 +11033,13 @@ static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold, "trigger a readahead.", NULL, NULL, 56, 0, 64, 0); +#ifdef UNIV_DEBUG +static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug, + PLUGIN_VAR_RQCMDARG, + "Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()", + NULL, NULL, 0, 0, 1024, 0); +#endif /* UNIV_DEBUG */ + static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(autoextend_increment), @@ -11094,6 +11101,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(random_read_ahead), MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(io_capacity), +#ifdef UNIV_DEBUG + MYSQL_SYSVAR(trx_rseg_n_slots_debug), +#endif /* UNIV_DEBUG */ NULL }; diff --git a/storage/innodb_plugin/include/trx0rseg.ic b/storage/innodb_plugin/include/trx0rseg.ic index daffa92fc7d..5e8d2b41120 100644 --- a/storage/innodb_plugin/include/trx0rseg.ic +++ b/storage/innodb_plugin/include/trx0rseg.ic @@ -25,6 +25,7 @@ Created 3/26/1996 Heikki Tuuri #include "srv0srv.h" #include "mtr0log.h" +#include "trx0sys.h" /******************************************************************//** Gets a rollback segment header. @@ -131,7 +132,13 @@ trx_rsegf_undo_find_free( ulint i; ulint page_no; - for (i = 0; i < TRX_RSEG_N_SLOTS; i++) { + for (i = 0; +#ifndef UNIV_DEBUG + i < TRX_RSEG_N_SLOTS; +#else + i < (trx_rseg_n_slots_debug ? trx_rseg_n_slots_debug : TRX_RSEG_N_SLOTS); +#endif + i++) { page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr); diff --git a/storage/innodb_plugin/include/trx0sys.h b/storage/innodb_plugin/include/trx0sys.h index 78bb6fc349b..56fb801ee42 100644 --- a/storage/innodb_plugin/include/trx0sys.h +++ b/storage/innodb_plugin/include/trx0sys.h @@ -229,6 +229,12 @@ trx_id_t trx_sys_get_new_trx_no(void); /*========================*/ #endif /* !UNIV_HOTBACKUP */ + +#ifdef UNIV_DEBUG +/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ +extern uint trx_rseg_n_slots_debug; +#endif + /*****************************************************************//** Writes a trx id to an index page. In case that the id size changes in some future version, this function should be used instead of diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 6f689f9909d..36aad4f8ca2 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -1900,6 +1900,20 @@ err_exit: } break; + case DB_TOO_MANY_CONCURRENT_TRXS: + /* We already have .ibd file here. it should be deleted. */ + + if (table->space && !fil_delete_tablespace(table->space)) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: not able to" + " delete tablespace %lu of table ", + (ulong) table->space); + ut_print_name(stderr, trx, TRUE, table->name); + fputs("!\n", stderr); + } + /* fall through */ + case DB_DUPLICATE_KEY: default: /* We may also get err == DB_ERROR if the .ibd file for the diff --git a/storage/innodb_plugin/trx/trx0sys.c b/storage/innodb_plugin/trx/trx0sys.c index 352fa6af219..e9328b27bba 100644 --- a/storage/innodb_plugin/trx/trx0sys.c +++ b/storage/innodb_plugin/trx/trx0sys.c @@ -127,6 +127,11 @@ static const char* file_format_name_map[] = { static const ulint FILE_FORMAT_NAME_N = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]); +#ifdef UNIV_DEBUG +/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ +uint trx_rseg_n_slots_debug = 0; +#endif + #ifndef UNIV_HOTBACKUP /** This is used to track the maximum file format id known to InnoDB. It's updated via SET GLOBAL innodb_file_format_check = 'x' or when we open |