From: Jon Olav Hauglid Date: December 17 2010 11:12am Subject: bzr commit into mysql-5.5-bugteam branch (jon.hauglid:3209) Bug#42230 List-Archive: http://lists.mysql.com/commits/127171 X-Bug: 42230 Message-Id: <201012171113.oBHBDfnv015209@rcsinet15.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3214065443964604979==" --===============3214065443964604979== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/x/mysql-5.5-bugteam-bug42230/ based on revid:jorgen.loland@stripped 3209 Jon Olav Hauglid 2010-12-17 Bug #42230 during add index, cannot do queries on storage engines that implement add_index The problem was that ALTER TABLE blocked reads on an InnoDB table while adding a secondary index, even if this was not needed. It is only needed for the final step where the .frm file is updated. The reason queries were blocked, was that ALTER TABLE upgraded the metadata lock from MDL_SHARED_NO_WRITE (which blocks writes) to MDL_EXCLUSIVE (which blocks all accesses) before index creation. The way the server handles index creation, is that storage engines publish their capabilities to the server and the server determines which of the following three ways this can be handled: 1) build a new version of the table; 2) change the existing table but with exclusive metadata lock; 3) change the existing table but without metadata lock upgrade. For InnoDB and secondary index creation, option 3) should have been selected. However this failed for two reasons. First, InnoDB did not publish this capability properly. Second, the ALTER TABLE code failed to made proper use of the information supplied by the storage engine. A variable need_lock_for_indexes was set accordingly, but was not later used. This patch fixes this problem by only doing metadata lock upgrade before index creation/deletion if this variable has been set. Test case added to innodb_mysql_sync.test. modified: mysql-test/r/innodb_mysql_sync.result mysql-test/t/innodb_mysql_sync.test sql/ha_partition.cc sql/handler.h sql/sql_table.cc storage/innobase/handler/ha_innodb.cc === modified file 'mysql-test/r/innodb_mysql_sync.result' --- a/mysql-test/r/innodb_mysql_sync.result 2010-06-25 07:07:18 +0000 +++ b/mysql-test/r/innodb_mysql_sync.result 2010-12-17 11:12:50 +0000 @@ -66,3 +66,23 @@ SELECT ((@id := id) - id) FROM t2; KILL @id; SET DEBUG_SYNC= "now SIGNAL killed"; DROP TABLE t1, t2; +SET DEBUG_SYNC= "RESET"; +# +# Bug#42230 during add index, cannot do queries on storage engines +# that implement add_index +# +DROP DATABASE IF EXISTS db1; +CREATE DATABASE db1; +CREATE TABLE db1.t1(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, value INT) engine=innodb; +INSERT INTO db1.t1(value) VALUES (1), (2); +SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query"; +ALTER TABLE db1.t1 ADD INDEX(value); +SET DEBUG_SYNC= "now WAIT_FOR manage"; +USE db1; +SELECT * FROM t1; +id value +1 1 +2 2 +SET DEBUG_SYNC= "now SIGNAL query"; +DROP DATABASE db1; +SET DEBUG_SYNC= "RESET"; === modified file 'mysql-test/t/innodb_mysql_sync.test' --- a/mysql-test/t/innodb_mysql_sync.test 2010-06-25 07:07:18 +0000 +++ b/mysql-test/t/innodb_mysql_sync.test 2010-12-17 11:12:50 +0000 @@ -104,6 +104,37 @@ SELECT ((@id := id) - id) FROM t2; KILL @id; SET DEBUG_SYNC= "now SIGNAL killed"; DROP TABLE t1, t2; +disconnect con1; +SET DEBUG_SYNC= "RESET"; + + +--echo # +--echo # Bug#42230 during add index, cannot do queries on storage engines +--echo # that implement add_index +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS db1; +--enable_warnings + +CREATE DATABASE db1; +CREATE TABLE db1.t1(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, value INT) engine=innodb; +INSERT INTO db1.t1(value) VALUES (1), (2); +SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query"; +--send ALTER TABLE db1.t1 ADD INDEX(value) + +connect(con1,localhost,root); +SET DEBUG_SYNC= "now WAIT_FOR manage"; +# Neither of these two statements should be blocked +USE db1; +SELECT * FROM t1; +SET DEBUG_SYNC= "now SIGNAL query"; + +connection default; +--reap +DROP DATABASE db1; +disconnect con1; +SET DEBUG_SYNC= "RESET"; # Check that all connections opened by test cases in this file are really === modified file 'sql/ha_partition.cc' --- a/sql/ha_partition.cc 2010-12-16 18:43:21 +0000 +++ b/sql/ha_partition.cc 2010-12-17 11:12:50 +0000 @@ -6430,28 +6430,28 @@ uint ha_partition::alter_table_flags(uin already altered, partitions. So both ADD and DROP can only be supported in pairs. */ - flags_to_check= HA_ONLINE_ADD_INDEX_NO_WRITES; - flags_to_check|= HA_ONLINE_DROP_INDEX_NO_WRITES; + flags_to_check= HA_INPLACE_ADD_INDEX_NO_READ_WRITE; + flags_to_check|= HA_INPLACE_DROP_INDEX_NO_READ_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES; - flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES; + flags_to_check= HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE; + flags_to_check|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_PK_INDEX_NO_WRITES; - flags_to_check|= HA_ONLINE_DROP_PK_INDEX_NO_WRITES; + flags_to_check= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; + flags_to_check|= HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_INDEX; - flags_to_check|= HA_ONLINE_DROP_INDEX; + flags_to_check= HA_INPLACE_ADD_INDEX_NO_WRITE; + flags_to_check|= HA_INPLACE_DROP_INDEX_NO_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_UNIQUE_INDEX; - flags_to_check|= HA_ONLINE_DROP_UNIQUE_INDEX; + flags_to_check= HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE; + flags_to_check|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; - flags_to_check= HA_ONLINE_ADD_PK_INDEX; - flags_to_check|= HA_ONLINE_DROP_PK_INDEX; + flags_to_check= HA_INPLACE_ADD_PK_INDEX_NO_WRITE; + flags_to_check|= HA_INPLACE_DROP_PK_INDEX_NO_WRITE; if ((flags_to_return & flags_to_check) != flags_to_check) flags_to_return&= ~flags_to_check; DBUG_RETURN(flags_to_return); === modified file 'sql/handler.h' --- a/sql/handler.h 2010-11-05 11:01:10 +0000 +++ b/sql/handler.h 2010-12-17 11:12:50 +0000 @@ -172,28 +172,31 @@ bits in alter_table_flags: */ /* - These bits are set if different kinds of indexes can be created - off-line without re-create of the table (but with a table lock). + These bits are set if different kinds of indexes can be created or dropped + in-place without re-creating the table using a temporary table. + NO_READ_WRITE indicates that the handler needs concurrent reads and writes + of table data to be blocked. Partitioning needs both ADD and DROP to be supported by its underlying handlers, due to error handling, see bug#57778. */ -#define HA_ONLINE_ADD_INDEX_NO_WRITES (1L << 0) /*add index w/lock*/ -#define HA_ONLINE_DROP_INDEX_NO_WRITES (1L << 1) /*drop index w/lock*/ -#define HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES (1L << 2) /*add unique w/lock*/ -#define HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES (1L << 3) /*drop uniq. w/lock*/ -#define HA_ONLINE_ADD_PK_INDEX_NO_WRITES (1L << 4) /*add prim. w/lock*/ -#define HA_ONLINE_DROP_PK_INDEX_NO_WRITES (1L << 5) /*drop prim. w/lock*/ +#define HA_INPLACE_ADD_INDEX_NO_READ_WRITE (1L << 0) +#define HA_INPLACE_DROP_INDEX_NO_READ_WRITE (1L << 1) +#define HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE (1L << 2) +#define HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE (1L << 3) +#define HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE (1L << 4) +#define HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE (1L << 5) /* - These are set if different kinds of indexes can be created on-line - (without a table lock). If a handler is capable of one or more of - these, it should also set the corresponding *_NO_WRITES bit(s). + These are set if different kinds of indexes can be created or dropped + in-place while still allowing concurrent reads (but not writes) of table + data. If a handler is capable of one or more of these, it should also set + the corresponding *_NO_READ_WRITE bit(s). */ -#define HA_ONLINE_ADD_INDEX (1L << 6) /*add index online*/ -#define HA_ONLINE_DROP_INDEX (1L << 7) /*drop index online*/ -#define HA_ONLINE_ADD_UNIQUE_INDEX (1L << 8) /*add unique online*/ -#define HA_ONLINE_DROP_UNIQUE_INDEX (1L << 9) /*drop uniq. online*/ -#define HA_ONLINE_ADD_PK_INDEX (1L << 10)/*add prim. online*/ -#define HA_ONLINE_DROP_PK_INDEX (1L << 11)/*drop prim. online*/ +#define HA_INPLACE_ADD_INDEX_NO_WRITE (1L << 6) +#define HA_INPLACE_DROP_INDEX_NO_WRITE (1L << 7) +#define HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE (1L << 8) +#define HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE (1L << 9) +#define HA_INPLACE_ADD_PK_INDEX_NO_WRITE (1L << 10) +#define HA_INPLACE_DROP_PK_INDEX_NO_WRITE (1L << 11) /* HA_PARTITION_FUNCTION_SUPPORTED indicates that the function is supported at all. === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2010-11-19 07:26:09 +0000 +++ b/sql/sql_table.cc 2010-12-17 11:12:50 +0000 @@ -4735,7 +4735,7 @@ err: @details Checks if any index is being modified (present as both DROP INDEX and ADD INDEX) in the current ALTER TABLE statement. Needed for disabling - online ALTER TABLE. + in-place ALTER TABLE. @param table The table being altered @param alter_info The ALTER TABLE structure @@ -4851,7 +4851,7 @@ mysql_compare_tables(TABLE *table, like to keep mysql_compare_tables() idempotent (not altering any of the arguments) we create a copy of alter_info here and pass it to mysql_prepare_create_table, then use the result - to evaluate possibility of fast ALTER TABLE, and then + to evaluate possibility of in-place ALTER TABLE, and then destroy the copy. */ Alter_info tmp_alter_info(*alter_info, thd->mem_root); @@ -4892,9 +4892,9 @@ mysql_compare_tables(TABLE *table, There was a bug prior to mysql-4.0.25. Number of null fields was calculated incorrectly. As a result frm and data files gets out of - sync after fast alter table. There is no way to determine by which + sync after in-place alter table. There is no way to determine by which mysql version (in 4.0 and 4.1 branches) table was created, thus we - disable fast alter table for all tables created by mysql versions + disable in-place alter table for all tables created by mysql versions prior to 5.0 branch. See BUG#6236. */ @@ -4917,7 +4917,7 @@ mysql_compare_tables(TABLE *table, } /* - Use transformed info to evaluate possibility of fast ALTER TABLE + Use transformed info to evaluate possibility of in-place ALTER TABLE but use the preserved field to persist modifications. */ new_field_it.init(alter_info->create_list); @@ -5197,7 +5197,7 @@ blob_length_by_type(enum_field_types typ semantic checks. This function is invoked when we know that we're going to - perform ALTER TABLE via a temporary table -- i.e. fast ALTER TABLE + perform ALTER TABLE via a temporary table -- i.e. in-place ALTER TABLE is not possible, perhaps because the ALTER statement contains instructions that require change in table data, not only in table definition or indexes. @@ -6092,7 +6092,7 @@ bool mysql_alter_table(THD *thd,char *ne } /* - If there are index changes only, try to do them online. "Index + If there are index changes only, try to do them in-place. "Index changes only" means also that the handler for the table does not change. The table is open and locked. The handler can be accessed. */ @@ -6100,8 +6100,8 @@ bool mysql_alter_table(THD *thd,char *ne { int pk_changed= 0; ulong alter_flags= 0; - ulong needed_online_flags= 0; - ulong needed_fast_flags= 0; + ulong needed_concurrent_read_flags= 0; + ulong needed_inplace_flags= 0; KEY *key; uint *idx_p; uint *idx_end_p; @@ -6125,8 +6125,8 @@ bool mysql_alter_table(THD *thd,char *ne { DBUG_PRINT("info", ("Dropping primary key")); /* Primary key. */ - needed_online_flags|= HA_ONLINE_DROP_PK_INDEX; - needed_fast_flags|= HA_ONLINE_DROP_PK_INDEX_NO_WRITES; + needed_concurrent_read_flags|= HA_INPLACE_DROP_PK_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE; pk_changed++; candidate_key_count--; } @@ -6136,8 +6136,8 @@ bool mysql_alter_table(THD *thd,char *ne bool is_candidate_key= true; /* Non-primary unique key. */ - needed_online_flags|= HA_ONLINE_DROP_UNIQUE_INDEX; - needed_fast_flags|= HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES; + needed_concurrent_read_flags|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE; /* Check if all fields in key are declared @@ -6156,12 +6156,12 @@ bool mysql_alter_table(THD *thd,char *ne else { /* Non-unique key. */ - needed_online_flags|= HA_ONLINE_DROP_INDEX; - needed_fast_flags|= HA_ONLINE_DROP_INDEX_NO_WRITES; + needed_concurrent_read_flags|= HA_INPLACE_DROP_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_DROP_INDEX_NO_READ_WRITE; } } no_pk= ((table->s->primary_key == MAX_KEY) || - (needed_online_flags & HA_ONLINE_DROP_PK_INDEX)); + (needed_concurrent_read_flags & HA_INPLACE_DROP_PK_INDEX_NO_WRITE)); /* Check added indexes. */ for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count; idx_p < idx_end_p; @@ -6199,57 +6199,59 @@ bool mysql_alter_table(THD *thd,char *ne { DBUG_PRINT("info", ("Adding primary key")); /* Primary key. */ - needed_online_flags|= HA_ONLINE_ADD_PK_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_PK_INDEX_NO_WRITES; + needed_concurrent_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; pk_changed++; no_pk= false; } else { /* Non-primary unique key. */ - needed_online_flags|= HA_ONLINE_ADD_UNIQUE_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES; + needed_concurrent_read_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE; } } else { /* Non-unique key. */ - needed_online_flags|= HA_ONLINE_ADD_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_INDEX_NO_WRITES; + needed_concurrent_read_flags|= HA_INPLACE_ADD_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_INDEX_NO_READ_WRITE; } } if ((candidate_key_count > 0) && - (needed_online_flags & HA_ONLINE_DROP_PK_INDEX)) + (needed_concurrent_read_flags & HA_INPLACE_DROP_PK_INDEX_NO_WRITE)) { /* Dropped primary key when there is some other unique not null key that should be converted to primary key */ - needed_online_flags|= HA_ONLINE_ADD_PK_INDEX; - needed_fast_flags|= HA_ONLINE_ADD_PK_INDEX_NO_WRITES; + needed_concurrent_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE; + needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE; pk_changed= 2; } - DBUG_PRINT("info", ("needed_online_flags: 0x%lx, needed_fast_flags: 0x%lx", - needed_online_flags, needed_fast_flags)); + DBUG_PRINT("info", + ("needed_concurrent_read_flags: 0x%lx, needed_inplace_flags: 0x%lx", + needed_concurrent_read_flags, needed_inplace_flags)); /* - Online or fast add/drop index is possible only if + In-place add/drop index is possible only if the primary key is not added and dropped in the same statement. Otherwise we have to recreate the table. need_copy_table is no-zero at this place. */ if ( pk_changed < 2 ) { - if ((alter_flags & needed_online_flags) == needed_online_flags) + if ((alter_flags & needed_concurrent_read_flags) == + needed_concurrent_read_flags) { - /* All required online flags are present. */ + /* All required flags to allow concurrent reads are present. */ need_copy_table= ALTER_TABLE_METADATA_ONLY; need_lock_for_indexes= FALSE; } - else if ((alter_flags & needed_fast_flags) == needed_fast_flags) + else if ((alter_flags & needed_inplace_flags) == needed_inplace_flags) { - /* All required fast flags are present. */ + /* All required in-place flags are present. */ need_copy_table= ALTER_TABLE_METADATA_ONLY; } } @@ -6403,10 +6405,14 @@ bool mysql_alter_table(THD *thd,char *ne } else { - if (!table->s->tmp_table && + if (alter_info->keys_onoff != LEAVE_AS_IS || + table->file->indexes_are_disabled()) + need_lock_for_indexes= true; + if (!table->s->tmp_table && need_lock_for_indexes && wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err_new_table_cleanup; thd_proc_info(thd, "manage keys"); + DEBUG_SYNC(thd, "alter_table_manage_keys"); alter_table_manage_keys(table, table->file->indexes_are_disabled(), alter_info->keys_onoff); error= trans_commit_stmt(thd); === modified file 'storage/innobase/handler/ha_innodb.cc' --- a/storage/innobase/handler/ha_innodb.cc 2010-12-16 18:43:21 +0000 +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-17 11:12:50 +0000 @@ -2573,11 +2573,12 @@ innobase_alter_table_flags( /*=======================*/ uint flags) { - return(HA_ONLINE_ADD_INDEX_NO_WRITES - | HA_ONLINE_DROP_INDEX_NO_WRITES - | HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES - | HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES - | HA_ONLINE_ADD_PK_INDEX_NO_WRITES); + return(HA_INPLACE_ADD_INDEX_NO_READ_WRITE + | HA_INPLACE_ADD_INDEX_NO_WRITE + | HA_INPLACE_DROP_INDEX_NO_READ_WRITE + | HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE + | HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE + | HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE); } /*****************************************************************//** --===============3214065443964604979== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jon.hauglid@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jon.hauglid@stripped # target_branch: file:///export/home/x/mysql-5.5-bugteam-bug42230/ # testament_sha1: 4aefcc41dd7030760727c2cae07b66d09608b9de # timestamp: 2010-12-17 12:12:54 +0100 # source_branch: file:///export/home/x/mysql-5.1-bugteam/ # base_revision_id: jorgen.loland@stripped\ # bw6y486ip401upg3 # # Begin bundle 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 gA== --===============3214065443964604979==--