mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
Bug#13635833: MULTIPLE CRASHES IN FOREIGN KEY CODE WITH CONCURRENT DDL/DML
There are two threads. In one thread, dml operation is going on involving cascaded update operation. In another thread, alter table add foreign key constraint is happening. Under these circumstances, it is possible for the dml thread to access a dict_foreign_t object that has been freed by the ddl thread. The debug sync test case provides the sequence of operations. Without fix, the test case will crash the server (because of newly added assert). With fix, the alter table stmt will return an error message. rb:947 approved by Jimmy Yang
This commit is contained in:
parent
a33079f854
commit
c1615df32c
12 changed files with 186 additions and 25 deletions
|
@ -1,5 +1,4 @@
|
|||
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
reserved
|
||||
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -11,8 +10,9 @@
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
||||
|
||||
|
||||
/* This file includes constants used with all databases */
|
||||
|
||||
|
@ -449,7 +449,8 @@ enum ha_base_keytype {
|
|||
#define HA_ERR_INDEX_COL_TOO_LONG 178 /* Index column length exceeds limit */
|
||||
#define HA_ERR_INDEX_CORRUPT 179 /* Index corrupted */
|
||||
#define HA_ERR_UNDO_REC_TOO_BIG 180 /* Undo log record too big */
|
||||
#define HA_ERR_LAST 180 /* Copy of last error nr */
|
||||
#define HA_ERR_TABLE_IN_FK_CHECK 181 /* Table being used in foreign key check */
|
||||
#define HA_ERR_LAST 181 /* Copy of last error nr */
|
||||
|
||||
/* Number of different errors */
|
||||
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
|
||||
|
|
45
mysql-test/suite/innodb/r/innodb_bug13635833.result
Normal file
45
mysql-test/suite/innodb/r/innodb_bug13635833.result
Normal file
|
@ -0,0 +1,45 @@
|
|||
SET DEBUG_SYNC='reset';
|
||||
create table t1 (f1 integer, key k1 (f1)) engine=innodb;
|
||||
create table t2 (f1 int, f2 int, key(f1), key(f2)) engine=innodb;
|
||||
create table t3 (f2 int, key(f2)) engine=innodb;
|
||||
insert into t1 values (10);
|
||||
insert into t2 values (10, 20);
|
||||
insert into t3 values (20);
|
||||
alter table t2 add constraint c1 foreign key (f1)
|
||||
references t1(f1) on update cascade;
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`f1` int(11) DEFAULT NULL,
|
||||
KEY `k1` (`f1`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
show create table t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
`f1` int(11) DEFAULT NULL,
|
||||
`f2` int(11) DEFAULT NULL,
|
||||
KEY `f1` (`f1`),
|
||||
KEY `f2` (`f2`),
|
||||
CONSTRAINT `c1` FOREIGN KEY (`f1`) REFERENCES `t1` (`f1`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
show create table t3;
|
||||
Table Create Table
|
||||
t3 CREATE TABLE `t3` (
|
||||
`f2` int(11) DEFAULT NULL,
|
||||
KEY `f2` (`f2`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
SET DEBUG_SYNC='innodb_rename_table_ready SIGNAL update_can_proceed
|
||||
WAIT_FOR dict_unfreeze';
|
||||
alter table t2 add constraint z1 foreign key (f2)
|
||||
references t3(f2) on update cascade;
|
||||
SET DEBUG_SYNC='innodb_row_update_for_mysql_begin
|
||||
WAIT_FOR update_can_proceed';
|
||||
SET DEBUG_SYNC='innodb_dml_cascade_dict_unfreeze SIGNAL dict_unfreeze
|
||||
WAIT_FOR foreign_free_cache';
|
||||
update ignore t1 set f1 = 20;
|
||||
ERROR HY000: Error on rename of './test/t2' to '#sql2-temporary' (errno: 181)
|
||||
SET DEBUG_SYNC='now SIGNAL foreign_free_cache';
|
||||
drop table t2;
|
||||
drop table t1;
|
||||
drop table t3;
|
||||
SET DEBUG_SYNC='reset';
|
64
mysql-test/suite/innodb/t/innodb_bug13635833.test
Normal file
64
mysql-test/suite/innodb/t/innodb_bug13635833.test
Normal file
|
@ -0,0 +1,64 @@
|
|||
--source include/have_innodb.inc
|
||||
--source include/have_debug_sync.inc
|
||||
--source include/not_embedded.inc
|
||||
|
||||
SET DEBUG_SYNC='reset';
|
||||
|
||||
# Save the initial number of concurrent sessions
|
||||
--source include/count_sessions.inc
|
||||
|
||||
create table t1 (f1 integer, key k1 (f1)) engine=innodb;
|
||||
create table t2 (f1 int, f2 int, key(f1), key(f2)) engine=innodb;
|
||||
create table t3 (f2 int, key(f2)) engine=innodb;
|
||||
|
||||
insert into t1 values (10);
|
||||
insert into t2 values (10, 20);
|
||||
insert into t3 values (20);
|
||||
|
||||
alter table t2 add constraint c1 foreign key (f1)
|
||||
references t1(f1) on update cascade;
|
||||
|
||||
show create table t1;
|
||||
show create table t2;
|
||||
show create table t3;
|
||||
|
||||
SET DEBUG_SYNC='innodb_rename_table_ready SIGNAL update_can_proceed
|
||||
WAIT_FOR dict_unfreeze';
|
||||
|
||||
--send
|
||||
alter table t2 add constraint z1 foreign key (f2)
|
||||
references t3(f2) on update cascade;
|
||||
|
||||
connect (thr2,localhost,root,,);
|
||||
connection thr2;
|
||||
|
||||
SET DEBUG_SYNC='innodb_row_update_for_mysql_begin
|
||||
WAIT_FOR update_can_proceed';
|
||||
SET DEBUG_SYNC='innodb_dml_cascade_dict_unfreeze SIGNAL dict_unfreeze
|
||||
WAIT_FOR foreign_free_cache';
|
||||
|
||||
--send
|
||||
update ignore t1 set f1 = 20;
|
||||
|
||||
connection default;
|
||||
--replace_regex /'[^']*test\/#sql2-[0-9a-f-]*'/'#sql2-temporary'/
|
||||
--error ER_ERROR_ON_RENAME
|
||||
reap;
|
||||
|
||||
SET DEBUG_SYNC='now SIGNAL foreign_free_cache';
|
||||
|
||||
connection thr2;
|
||||
reap;
|
||||
disconnect thr2;
|
||||
--source include/wait_until_disconnected.inc
|
||||
|
||||
connection default;
|
||||
|
||||
drop table t2;
|
||||
drop table t1;
|
||||
drop table t3;
|
||||
|
||||
# Wait till we reached the initial number of concurrent sessions
|
||||
--source include/wait_until_count_sessions.inc
|
||||
|
||||
SET DEBUG_SYNC='reset';
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef MYSYS_MY_HANDLER_ERRORS_INCLUDED
|
||||
#define MYSYS_MY_HANDLER_ERRORS_INCLUDED
|
||||
|
||||
/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
/* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -13,8 +13,8 @@
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
||||
|
||||
/*
|
||||
Errors a handler can give you
|
||||
|
@ -83,7 +83,8 @@ static const char *handler_error_messages[]=
|
|||
"Too many active concurrent transactions",
|
||||
"Index column length exceeds limit",
|
||||
"Index corrupted",
|
||||
"Undo record too big"
|
||||
"Undo record too big",
|
||||
"Table is being used in foreign key check"
|
||||
};
|
||||
|
||||
extern void my_handler_error_register(void);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -10,8 +10,8 @@
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
||||
|
||||
/** @file handler.cc
|
||||
|
||||
|
@ -359,6 +359,7 @@ int ha_init_errors(void)
|
|||
SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS));
|
||||
SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG));
|
||||
SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT));
|
||||
SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
|
||||
|
||||
/* Register the error messages for use with my_error(). */
|
||||
return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
|
||||
|
@ -2878,6 +2879,9 @@ void handler::print_error(int error, myf errflag)
|
|||
case HA_ERR_UNDO_REC_TOO_BIG:
|
||||
textno= ER_UNDO_RECORD_TOO_BIG;
|
||||
break;
|
||||
case HA_ERR_TABLE_IN_FK_CHECK:
|
||||
textno= ER_TABLE_IN_FK_CHECK;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
/* The error was "unknown" to this function.
|
||||
|
|
|
@ -6494,3 +6494,6 @@ ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT
|
|||
ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC
|
||||
eng "CREATE TABLE... SELECT... on a table with an auto-increment column is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are inserted. This order cannot be predicted and may differ on master and the slave."
|
||||
|
||||
ER_TABLE_IN_FK_CHECK
|
||||
eng "Table is being used in foreign key check."
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
|
@ -55,6 +55,8 @@ UNIV_INTERN dict_index_t* dict_ind_compact;
|
|||
#include "m_ctype.h" /* my_isspace() */
|
||||
#include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
|
||||
#include "row0upd.h"
|
||||
#include "m_string.h"
|
||||
#include "my_sys.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
@ -2329,6 +2331,8 @@ dict_foreign_free(
|
|||
/*==============*/
|
||||
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
|
||||
{
|
||||
ut_a(foreign->foreign_table->n_foreign_key_checks_running == 0);
|
||||
|
||||
mem_heap_free(foreign->heap);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, 2009 Google Inc.
|
||||
Copyright (c) 2009, Percona Inc.
|
||||
|
||||
|
@ -998,6 +998,9 @@ convert_error_code_to_mysql(
|
|||
case DB_OUT_OF_FILE_SPACE:
|
||||
return(HA_ERR_RECORD_FILE_FULL);
|
||||
|
||||
case DB_TABLE_IN_FK_CHECK:
|
||||
return(HA_ERR_TABLE_IN_FK_CHECK);
|
||||
|
||||
case DB_TABLE_IS_BEING_USED:
|
||||
return(HA_ERR_WRONG_COMMAND);
|
||||
|
||||
|
@ -7573,6 +7576,8 @@ innobase_rename_table(
|
|||
normalize_table_name(norm_to, to);
|
||||
normalize_table_name(norm_from, from);
|
||||
|
||||
DEBUG_SYNC_C("innodb_rename_table_ready");
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
|
@ -112,6 +112,8 @@ enum db_err {
|
|||
limit */
|
||||
DB_INDEX_CORRUPT, /* we have corrupted index */
|
||||
DB_UNDO_RECORD_TOO_BIG, /* the undo log record is too big */
|
||||
DB_TABLE_IN_FK_CHECK, /* table is being used in foreign
|
||||
key check */
|
||||
|
||||
/* The following are partial failure codes */
|
||||
DB_FAIL = 1000,
|
||||
|
|
|
@ -49,6 +49,8 @@ Created 4/20/1996 Heikki Tuuri
|
|||
#include "data0data.h"
|
||||
#include "usr0sess.h"
|
||||
#include "buf0lru.h"
|
||||
#include "m_string.h"
|
||||
#include "my_sys.h"
|
||||
|
||||
#define ROW_INS_PREV 1
|
||||
#define ROW_INS_NEXT 2
|
||||
|
@ -1085,6 +1087,9 @@ row_ins_foreign_check_on_constraint(
|
|||
release the latch. */
|
||||
|
||||
row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
|
||||
|
||||
DEBUG_SYNC_C("innodb_dml_cascade_dict_unfreeze");
|
||||
|
||||
row_mysql_freeze_data_dictionary(thr_get_trx(thr));
|
||||
|
||||
mtr_start(mtr);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
|
@ -51,6 +51,9 @@ Created 9/17/2000 Heikki Tuuri
|
|||
#include "btr0sea.h"
|
||||
#include "fil0fil.h"
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "m_string.h"
|
||||
#include "my_sys.h"
|
||||
|
||||
|
||||
/** Provide optional 4.x backwards compatibility for 5.0 and above */
|
||||
UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
|
||||
|
@ -1443,6 +1446,8 @@ row_update_for_mysql(
|
|||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
DEBUG_SYNC_C("innodb_row_update_for_mysql_begin");
|
||||
|
||||
trx->op_info = "updating or deleting";
|
||||
|
||||
row_mysql_delay_if_needed();
|
||||
|
@ -3803,6 +3808,7 @@ row_rename_table_for_mysql(
|
|||
ulint n_constraints_to_drop = 0;
|
||||
ibool old_is_tmp, new_is_tmp;
|
||||
pars_info_t* info = NULL;
|
||||
int retry;
|
||||
|
||||
ut_a(old_name != NULL);
|
||||
ut_a(new_name != NULL);
|
||||
|
@ -3885,6 +3891,25 @@ row_rename_table_for_mysql(
|
|||
}
|
||||
}
|
||||
|
||||
/* Is a foreign key check running on this table? */
|
||||
for (retry = 0; retry < 100
|
||||
&& table->n_foreign_key_checks_running > 0; ++retry) {
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
os_thread_yield();
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
}
|
||||
|
||||
if (table->n_foreign_key_checks_running > 0) {
|
||||
ut_print_timestamp(stderr);
|
||||
fputs(" InnoDB: Error: in ALTER TABLE ", stderr);
|
||||
ut_print_name(stderr, trx, TRUE, old_name);
|
||||
fprintf(stderr, "\n"
|
||||
"InnoDB: a FOREIGN KEY check is running.\n"
|
||||
"InnoDB: Cannot rename table.\n");
|
||||
err = DB_TABLE_IN_FK_CHECK;
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
/* We use the private SQL parser of Innobase to generate the query
|
||||
graphs needed in updating the dictionary data from system tables. */
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, Oracle Corpn. All Rights Reserved.
|
||||
Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
|
@ -718,6 +718,8 @@ ut_strerr(
|
|||
return("Undo record too big");
|
||||
case DB_END_OF_INDEX:
|
||||
return("End of index");
|
||||
case DB_TABLE_IN_FK_CHECK:
|
||||
return("Table is being used in foreign key check");
|
||||
/* do not add default: in order to produce a warning if new code
|
||||
is added to the enum but not added here */
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue