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,
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
};
......
......@@ -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);
......
......@@ -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. */
......
......@@ -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);
......
......@@ -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. */
......
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:
......
......@@ -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
};
......
......@@ -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);
......
......@@ -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
......
......@@ -1900,6 +1900,20 @@ row_create_table_for_mysql(
}
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
......
......@@ -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
......
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