Manual merge from mysql-5.1-bugteam to mysql-trunk-merge.
Conflicts: Text conflict in sql/sql_base.cc Text conflict in sql/sql_partition.cc Text conflict in sql/sql_priv.h Text conflict in sql/sql_show.cc
This commit is contained in:
commit
a6cf28a7a1
61
mysql-test/suite/parts/r/partition_debug_sync_innodb.result
Normal file
61
mysql-test/suite/parts/r/partition_debug_sync_innodb.result
Normal file
@ -0,0 +1,61 @@
|
||||
#
|
||||
# Bug#50561: ALTER PARTITIONS does not have adequate lock, breaks with
|
||||
# concurrent I_S query
|
||||
create table t1 (a int)
|
||||
engine = innodb
|
||||
partition by range (a)
|
||||
(partition p0 values less than MAXVALUE);
|
||||
insert into t1 values (1), (11), (21), (33);
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
1
|
||||
11
|
||||
21
|
||||
33
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
/*!50100 PARTITION BY RANGE (a)
|
||||
(PARTITION p0 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
|
||||
t1#P#p0.ibd
|
||||
t1.frm
|
||||
t1.par
|
||||
SET DEBUG_SYNC='before_open_in_get_all_tables SIGNAL parked WAIT_FOR open';
|
||||
SET DEBUG_SYNC='partition_open_error SIGNAL alter WAIT_FOR finish';
|
||||
SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test';
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR parked';
|
||||
# When waiting for the name lock in get_all_tables in sql_show.cc
|
||||
# this will not be concurrent any more, thus the TIMEOUT
|
||||
SET DEBUG_SYNC = 'before_rename_partitions SIGNAL open WAIT_FOR alter TIMEOUT 1';
|
||||
# Needs to be executed twice, since first is this 'SET DEBUG_SYNC ...'
|
||||
SET DEBUG_SYNC = 'before_close_thread_tables SIGNAL finish EXECUTE 2';
|
||||
ALTER TABLE t1 REORGANIZE PARTITION p0 INTO
|
||||
(PARTITION p0 VALUES LESS THAN (10),
|
||||
PARTITION p10 VALUES LESS THAN MAXVALUE);
|
||||
Warnings:
|
||||
Warning 1639 debug sync point wait timed out
|
||||
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME
|
||||
def test t1 p0 NULL 1 NULL RANGE NULL a NULL 10 1 16384 16384 NULL 0 0 NULL NULL NULL NULL default NULL
|
||||
def test t1 p10 NULL 2 NULL RANGE NULL a NULL MAXVALUE 3 5461 16384 NULL 0 0 NULL NULL NULL NULL default NULL
|
||||
t1#P#p0.ibd
|
||||
t1#P#p10.ibd
|
||||
t1.frm
|
||||
t1.par
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
/*!50100 PARTITION BY RANGE (a)
|
||||
(PARTITION p0 VALUES LESS THAN (10) ENGINE = InnoDB,
|
||||
PARTITION p10 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
1
|
||||
11
|
||||
21
|
||||
33
|
||||
drop table t1;
|
||||
SET DEBUG_SYNC = 'RESET';
|
@ -0,0 +1 @@
|
||||
--innodb_file_per_table=1
|
44
mysql-test/suite/parts/t/partition_debug_sync_innodb.test
Normal file
44
mysql-test/suite/parts/t/partition_debug_sync_innodb.test
Normal file
@ -0,0 +1,44 @@
|
||||
--source include/have_innodb.inc
|
||||
--source include/have_partition.inc
|
||||
--source include/have_debug_sync.inc
|
||||
|
||||
let $MYSQLD_DATADIR=`SELECT @@datadir`;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#50561: ALTER PARTITIONS does not have adequate lock, breaks with
|
||||
--echo # concurrent I_S query
|
||||
create table t1 (a int)
|
||||
engine = innodb
|
||||
partition by range (a)
|
||||
(partition p0 values less than MAXVALUE);
|
||||
insert into t1 values (1), (11), (21), (33);
|
||||
SELECT * FROM t1;
|
||||
SHOW CREATE TABLE t1;
|
||||
--list_files $MYSQLD_DATADIR/test
|
||||
|
||||
SET DEBUG_SYNC='before_open_in_get_all_tables SIGNAL parked WAIT_FOR open';
|
||||
SET DEBUG_SYNC='partition_open_error SIGNAL alter WAIT_FOR finish';
|
||||
send
|
||||
SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1' AND TABLE_SCHEMA = 'test';
|
||||
|
||||
connect (con1, localhost, root,,);
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR parked';
|
||||
--echo # When waiting for the name lock in get_all_tables in sql_show.cc
|
||||
--echo # this will not be concurrent any more, thus the TIMEOUT
|
||||
SET DEBUG_SYNC = 'before_rename_partitions SIGNAL open WAIT_FOR alter TIMEOUT 1';
|
||||
--echo # Needs to be executed twice, since first is this 'SET DEBUG_SYNC ...'
|
||||
SET DEBUG_SYNC = 'before_close_thread_tables SIGNAL finish EXECUTE 2';
|
||||
--error 0,ER_TABLE_EXISTS_ERROR
|
||||
ALTER TABLE t1 REORGANIZE PARTITION p0 INTO
|
||||
(PARTITION p0 VALUES LESS THAN (10),
|
||||
PARTITION p10 VALUES LESS THAN MAXVALUE);
|
||||
|
||||
disconnect con1;
|
||||
connection default;
|
||||
--reap
|
||||
--list_files $MYSQLD_DATADIR/test
|
||||
SHOW CREATE TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
drop table t1;
|
||||
--list_files $MYSQLD_DATADIR/test
|
||||
SET DEBUG_SYNC = 'RESET';
|
@ -80,6 +80,7 @@ struct show_table_authors_st show_table_authors[]= {
|
||||
{ "Eric Herman", "Amsterdam, Netherlands", "Bug fixing - federated" },
|
||||
{ "Andrey Hristov", "Walldorf, Germany", "Event scheduler (5.1)" },
|
||||
{ "Alexander (Alexi) Ivanov", "St. Petersburg, Russia", "Replication" },
|
||||
{ "Mattias Jonsson", "Uppsala, Sweden", "Partitioning" },
|
||||
{ "Alexander (Salle) Keremidarski", "Sofia, Bulgaria",
|
||||
"Bug fixing" },
|
||||
{ "Mats Kindahl", "Storvreta, Sweden", "Replication" },
|
||||
|
@ -60,6 +60,8 @@
|
||||
#include "key.h"
|
||||
#include "sql_plugin.h"
|
||||
|
||||
#include "debug_sync.h"
|
||||
|
||||
static const char *ha_par_ext= ".par";
|
||||
#ifdef NOT_USED
|
||||
static int free_share(PARTITION_SHARE * share);
|
||||
@ -692,6 +694,7 @@ int ha_partition::rename_partitions(const char *path)
|
||||
DBUG_ASSERT(!strcmp(path, get_canonical_filename(m_file[0], path,
|
||||
norm_name_buff)));
|
||||
|
||||
DEBUG_SYNC(ha_thd(), "before_rename_partitions");
|
||||
if (temp_partitions)
|
||||
{
|
||||
/*
|
||||
@ -2684,6 +2687,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err_handler:
|
||||
DEBUG_SYNC(ha_thd(), "partition_open_error");
|
||||
while (file-- != m_file)
|
||||
(*file)->close();
|
||||
bitmap_free(&m_bulk_insert_started);
|
||||
|
@ -1418,6 +1418,12 @@ void close_thread_tables(THD *thd)
|
||||
table->s->table_name.str, (long) table));
|
||||
#endif
|
||||
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
/* debug_sync may not be initialized for some slave threads */
|
||||
if (thd->debug_sync_control)
|
||||
DEBUG_SYNC(thd, "before_close_thread_tables");
|
||||
#endif
|
||||
|
||||
/* Detach MERGE children after every statement. Even under LOCK TABLES. */
|
||||
for (table= thd->open_tables; table; table= table->next)
|
||||
{
|
||||
@ -5242,8 +5248,8 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
|
||||
thd - thread handler
|
||||
tables - list of tables for open
|
||||
flags - bitmap of flags to modify how the tables will be open:
|
||||
MYSQL_OPEN_IGNORE_FLUSH - open table even if someone has
|
||||
done a flush or namelock on it.
|
||||
MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
|
||||
done a flush on it.
|
||||
|
||||
RETURN
|
||||
FALSE - ok
|
||||
@ -8782,8 +8788,57 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
|
||||
|
||||
|
||||
/*
|
||||
Unlock and close table before renaming and dropping partitions
|
||||
SYNOPSIS
|
||||
abort_and_upgrade_lock()
|
||||
alter_close_tables()
|
||||
lpt Struct carrying parameters
|
||||
RETURN VALUES
|
||||
0
|
||||
*/
|
||||
|
||||
static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
{
|
||||
TABLE_SHARE *share= lpt->table->s;
|
||||
THD *thd= lpt->thd;
|
||||
TABLE *table;
|
||||
DBUG_ENTER("alter_close_tables");
|
||||
/*
|
||||
We must keep LOCK_open while manipulating with thd->open_tables.
|
||||
Another thread may be working on it.
|
||||
*/
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
/*
|
||||
We can safely remove locks for all tables with the same name:
|
||||
later they will all be closed anyway in
|
||||
alter_partition_lock_handling().
|
||||
*/
|
||||
for (table= thd->open_tables; table ; table= table->next)
|
||||
{
|
||||
if (!strcmp(table->s->table_name.str, share->table_name.str) &&
|
||||
!strcmp(table->s->db.str, share->db.str))
|
||||
{
|
||||
mysql_lock_remove(thd, thd->lock, table);
|
||||
table->file->close();
|
||||
table->db_stat= 0; // Mark file closed
|
||||
/*
|
||||
Ensure that we won't end up with a crippled table instance
|
||||
in the table cache if an error occurs before we reach
|
||||
alter_partition_lock_handling() and the table is closed
|
||||
by close_thread_tables() instead.
|
||||
*/
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
|
||||
table->s->db.str,
|
||||
table->s->table_name.str);
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
SYNOPSIS
|
||||
abort_and_upgrade_lock_and_close_table()
|
||||
lpt Parameter passing struct
|
||||
All parameters passed through the ALTER_PARTITION_PARAM_TYPE object
|
||||
RETURN VALUE
|
||||
@ -8792,7 +8847,7 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
|
||||
Remember old lock level (for possible downgrade later on), abort all
|
||||
waiting threads and ensure that all keeping locks currently are
|
||||
completed such that we own the lock exclusively and no other interaction
|
||||
is ongoing.
|
||||
is ongoing. Close the table and hold the name lock.
|
||||
|
||||
thd Thread object
|
||||
table Table object
|
||||
@ -8801,12 +8856,14 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
|
||||
old_lock_level Old lock level
|
||||
*/
|
||||
|
||||
int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
int abort_and_upgrade_lock_and_close_table(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
{
|
||||
DBUG_ENTER("abort_and_upgrade_lock");
|
||||
DBUG_ENTER("abort_and_upgrade_lock_and_close_table");
|
||||
|
||||
if (wait_while_table_is_used(lpt->thd, lpt->table, HA_EXTRA_FORCE_REOPEN))
|
||||
DBUG_RETURN(1);
|
||||
if (alter_close_tables(lpt))
|
||||
DBUG_RETURN(1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
|
||||
thr_lock_type lock_type, uint flags);
|
||||
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
|
||||
bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
|
||||
int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt);
|
||||
int abort_and_upgrade_lock_and_close_table(ALTER_PARTITION_PARAM_TYPE *lpt);
|
||||
int decide_logging_format(THD *thd, TABLE_LIST *tables);
|
||||
void free_io_cache(TABLE *entry);
|
||||
void intern_close_table(TABLE *entry);
|
||||
|
@ -6283,54 +6283,6 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
|
||||
}
|
||||
|
||||
/*
|
||||
Unlock and close table before renaming and dropping partitions
|
||||
SYNOPSIS
|
||||
alter_close_tables()
|
||||
lpt Struct carrying parameters
|
||||
RETURN VALUES
|
||||
0
|
||||
*/
|
||||
|
||||
static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
{
|
||||
TABLE_SHARE *share= lpt->table->s;
|
||||
THD *thd= lpt->thd;
|
||||
TABLE *table;
|
||||
DBUG_ENTER("alter_close_tables");
|
||||
/*
|
||||
We must keep LOCK_open while manipulating with thd->open_tables.
|
||||
Another thread may be working on it.
|
||||
*/
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
/*
|
||||
We can safely remove locks for all tables with the same name:
|
||||
later they will all be closed anyway in
|
||||
alter_partition_lock_handling().
|
||||
*/
|
||||
for (table= thd->open_tables; table ; table= table->next)
|
||||
{
|
||||
if (!strcmp(table->s->table_name.str, share->table_name.str) &&
|
||||
!strcmp(table->s->db.str, share->db.str))
|
||||
{
|
||||
mysql_lock_remove(thd, thd->lock, table);
|
||||
table->file->close();
|
||||
table->db_stat= 0; // Mark file closed
|
||||
/*
|
||||
Ensure that we won't end up with a crippled table instance
|
||||
in the table cache if an error occurs before we reach
|
||||
alter_partition_lock_handling() and the table is closed
|
||||
by close_thread_tables() instead.
|
||||
*/
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
|
||||
table->s->db.str,
|
||||
table->s->table_name.str);
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Handle errors for ALTER TABLE for partitioning
|
||||
@ -6629,9 +6581,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
|
||||
write_log_drop_partition(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_drop_partition_3") ||
|
||||
(not_completed= FALSE) ||
|
||||
abort_and_upgrade_lock(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_drop_partition_4") ||
|
||||
alter_close_tables(lpt) ||
|
||||
abort_and_upgrade_lock_and_close_table(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_drop_partition_5") ||
|
||||
((!thd->lex->no_write_to_binlog) &&
|
||||
(write_bin_log(thd, FALSE,
|
||||
@ -6697,9 +6647,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
|
||||
ERROR_INJECT_CRASH("crash_add_partition_2") ||
|
||||
mysql_change_partitions(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_add_partition_3") ||
|
||||
abort_and_upgrade_lock(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_add_partition_4") ||
|
||||
alter_close_tables(lpt) ||
|
||||
abort_and_upgrade_lock_and_close_table(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_add_partition_5") ||
|
||||
((!thd->lex->no_write_to_binlog) &&
|
||||
(write_bin_log(thd, FALSE,
|
||||
@ -6782,9 +6730,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
|
||||
write_log_final_change_partition(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_change_partition_4") ||
|
||||
(not_completed= FALSE) ||
|
||||
abort_and_upgrade_lock(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_change_partition_5") ||
|
||||
alter_close_tables(lpt) ||
|
||||
abort_and_upgrade_lock_and_close_table(lpt) ||
|
||||
ERROR_INJECT_CRASH("crash_change_partition_6") ||
|
||||
((!thd->lex->no_write_to_binlog) &&
|
||||
(write_bin_log(thd, FALSE,
|
||||
|
@ -49,7 +49,8 @@
|
||||
#include "event_data_objects.h"
|
||||
#endif
|
||||
#include <my_dir.h>
|
||||
#include "lock.h" // MYSQL_LOCK_IGNORE_FLUSH
|
||||
#include "debug_sync.h"
|
||||
#include "lock.h" // MYSQL_OPEN_IGNORE_FLUSH
|
||||
|
||||
#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
|
||||
|
||||
@ -3538,6 +3539,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
show_table_list->i_s_requested_object=
|
||||
schema_table->i_s_requested_object;
|
||||
DEBUG_SYNC(thd, "before_open_in_get_all_tables");
|
||||
res= open_normal_and_derived_tables(thd, show_table_list,
|
||||
(MYSQL_OPEN_IGNORE_FLUSH |
|
||||
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
|
||||
|
Loading…
x
Reference in New Issue
Block a user