Commit 115f5e85 authored by Yasufumi Kinoshita's avatar Yasufumi Kinoshita

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
parent 13b26548
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;
--max_connections=64 --innodb_thread_concurrency=0 --innodb_file_per_table
# 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
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;
--max_connections=64 --innodb_thread_concurrency=0 --innodb_file_per_table
# 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
...@@ -9060,6 +9060,13 @@ static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug, ...@@ -9060,6 +9060,13 @@ static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
NULL, NULL, 0, 0, 1, 0); NULL, NULL, 0, 0, 1, 0);
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ #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[]= { static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(additional_mem_pool_size),
MYSQL_SYSVAR(autoextend_increment), MYSQL_SYSVAR(autoextend_increment),
...@@ -9105,6 +9112,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { ...@@ -9105,6 +9112,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
MYSQL_SYSVAR(change_buffering_debug), MYSQL_SYSVAR(change_buffering_debug),
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
#ifdef UNIV_DEBUG
MYSQL_SYSVAR(trx_rseg_n_slots_debug),
#endif /* UNIV_DEBUG */
NULL NULL
}; };
......
...@@ -8,6 +8,7 @@ Created 3/26/1996 Heikki Tuuri ...@@ -8,6 +8,7 @@ Created 3/26/1996 Heikki Tuuri
#include "srv0srv.h" #include "srv0srv.h"
#include "mtr0log.h" #include "mtr0log.h"
#include "trx0sys.h"
/********************************************************************** /**********************************************************************
Gets a rollback segment header. */ Gets a rollback segment header. */
...@@ -113,7 +114,13 @@ trx_rsegf_undo_find_free( ...@@ -113,7 +114,13 @@ trx_rsegf_undo_find_free(
ulint i; ulint i;
ulint page_no; 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); page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr);
......
...@@ -47,6 +47,11 @@ extern ibool trx_doublewrite_buf_is_being_created; ...@@ -47,6 +47,11 @@ extern ibool trx_doublewrite_buf_is_being_created;
extern ibool trx_doublewrite_must_reset_space_ids; extern ibool trx_doublewrite_must_reset_space_ids;
extern ibool trx_sys_multiple_tablespace_format; 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 Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page. */ doublewrite buffer is placed on the trx system header page. */
......
...@@ -1948,6 +1948,18 @@ row_create_table_for_mysql( ...@@ -1948,6 +1948,18 @@ row_create_table_for_mysql(
FALSE); 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) { } else if (err == DB_DUPLICATE_KEY) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
......
...@@ -54,6 +54,10 @@ InnoDB. */ ...@@ -54,6 +54,10 @@ InnoDB. */
char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN]; char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
ib_longlong trx_sys_mysql_bin_log_pos = -1; 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. */ Determines if a page number is located inside the doublewrite buffer. */
......
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 2011-12-21 The InnoDB Team
* include/ut0rnd.ic: * include/ut0rnd.ic:
......
...@@ -11033,6 +11033,13 @@ static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold, ...@@ -11033,6 +11033,13 @@ static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
"trigger a readahead.", "trigger a readahead.",
NULL, NULL, 56, 0, 64, 0); 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[]= { static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(additional_mem_pool_size),
MYSQL_SYSVAR(autoextend_increment), MYSQL_SYSVAR(autoextend_increment),
...@@ -11094,6 +11101,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { ...@@ -11094,6 +11101,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(random_read_ahead), MYSQL_SYSVAR(random_read_ahead),
MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(read_ahead_threshold),
MYSQL_SYSVAR(io_capacity), MYSQL_SYSVAR(io_capacity),
#ifdef UNIV_DEBUG
MYSQL_SYSVAR(trx_rseg_n_slots_debug),
#endif /* UNIV_DEBUG */
NULL NULL
}; };
......
...@@ -25,6 +25,7 @@ Created 3/26/1996 Heikki Tuuri ...@@ -25,6 +25,7 @@ Created 3/26/1996 Heikki Tuuri
#include "srv0srv.h" #include "srv0srv.h"
#include "mtr0log.h" #include "mtr0log.h"
#include "trx0sys.h"
/******************************************************************//** /******************************************************************//**
Gets a rollback segment header. Gets a rollback segment header.
...@@ -131,7 +132,13 @@ trx_rsegf_undo_find_free( ...@@ -131,7 +132,13 @@ trx_rsegf_undo_find_free(
ulint i; ulint i;
ulint page_no; 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); page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr);
......
...@@ -229,6 +229,12 @@ trx_id_t ...@@ -229,6 +229,12 @@ trx_id_t
trx_sys_get_new_trx_no(void); trx_sys_get_new_trx_no(void);
/*========================*/ /*========================*/
#endif /* !UNIV_HOTBACKUP */ #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 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 some future version, this function should be used instead of
......
...@@ -1900,6 +1900,20 @@ err_exit: ...@@ -1900,6 +1900,20 @@ err_exit:
} }
break; 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: case DB_DUPLICATE_KEY:
default: default:
/* We may also get err == DB_ERROR if the .ibd file for the /* We may also get err == DB_ERROR if the .ibd file for the
......
...@@ -127,6 +127,11 @@ static const char* file_format_name_map[] = { ...@@ -127,6 +127,11 @@ static const char* file_format_name_map[] = {
static const ulint FILE_FORMAT_NAME_N static const ulint FILE_FORMAT_NAME_N
= sizeof(file_format_name_map) / sizeof(file_format_name_map[0]); = 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 #ifndef UNIV_HOTBACKUP
/** This is used to track the maximum file format id known to InnoDB. It's /** 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 updated via SET GLOBAL innodb_file_format_check = 'x' or when we open
......
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