List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:January 26 2011 1:59pm
Subject:bzr push into mysql-5.5 branch (jon.hauglid:3277 to 3278) Bug#42230
View as plain text  
 3278 Jon Olav Hauglid	2011-01-26
      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.
      
      This patch also changes some of the related terminology used 
      in the code. Specifically the use of "fast" and "online" with
      respect to ALTER TABLE. "Fast" was used to indicate that an
      ALTER TABLE operation could be done without involving a
      temporary table. "Fast" has been renamed "in-place" to more
      accurately describe the behavior.
      
      "Online" meant that the operation could be done without taking
      a table lock. However, in the current implementation writes
      are always prohibited during ALTER TABLE and an exclusive
      metadata lock is held while updating the .frm, so ALTER TABLE
      is not completely online. This patch replaces "online" with 
      "in-place", with additional comments indicating if concurrent
      reads are allowed during index creation/deletion or not.
      
      An important part of this update of terminology is renaming
      of the handler flags used by handlers to indicate if index
      creation/deletion can be done in-place and if concurrent reads
      are allowed. For example, the HA_ONLINE_ADD_INDEX_NO_WRITES
      flag has been renamed to HA_INPLACE_ADD_INDEX_NO_READ_WRITE,
      while HA_ONLINE_ADD_INDEX is now HA_INPLACE_ADD_INDEX_NO_WRITE.
      Note that this is a rename to clarify current behavior, the
      flag values have not changed and no flags have been removed or
      added.
      
      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
 3277 Alfranio Correia	2011-01-26 [merge]
      merge mysql-5.1 --> mysql-5.5

    modified:
      mysql-test/suite/rpl/t/disabled.def
=== modified file 'mysql-test/r/innodb_mysql_sync.result'
--- a/mysql-test/r/innodb_mysql_sync.result	2011-01-10 13:12:23 +0000
+++ b/mysql-test/r/innodb_mysql_sync.result	2011-01-26 13:23:29 +0000
@@ -90,3 +90,68 @@ test.t1	optimize	status	Operation failed
 # Connection default
 DROP TABLE t1;
 SET DEBUG_SYNC= 'RESET';
+#
+# Bug#42230 during add index, cannot do queries on storage engines
+#           that implement add_index
+#
+DROP DATABASE IF EXISTS db1;
+DROP TABLE IF EXISTS t1;
+# Test 1: Secondary index, should not block reads (original test case).
+# Connection default
+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";
+# Sending:
+ALTER TABLE db1.t1 ADD INDEX(value);
+# Connection con1
+SET DEBUG_SYNC= "now WAIT_FOR manage";
+USE db1;
+SELECT * FROM t1;
+id	value
+1	1
+2	2
+SET DEBUG_SYNC= "now SIGNAL query";
+# Connection default
+# Reaping: ALTER TABLE db1.t1 ADD INDEX(value)
+DROP DATABASE db1;
+# Test 2: Primary index (implicit), should block reads.
+CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL) engine=innodb;
+SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query";
+# Sending:
+ALTER TABLE t1 ADD UNIQUE INDEX(a);
+# Connection con1
+SET DEBUG_SYNC= "now WAIT_FOR manage";
+USE test;
+# Sending:
+SELECT * FROM t1;
+# Connection con2
+# Waiting for SELECT to be blocked by the metadata lock on t1
+SET DEBUG_SYNC= "now SIGNAL query";
+# Connection default
+# Reaping: ALTER TABLE t1 ADD UNIQUE INDEX(a)
+# Connection con1
+# Reaping: SELECT * FROM t1
+a	b
+# Test 3: Primary index (explicit), should block reads.
+# Connection default
+ALTER TABLE t1 DROP INDEX a;
+SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query";
+# Sending:
+ALTER TABLE t1 ADD PRIMARY KEY (a);
+# Connection con1
+SET DEBUG_SYNC= "now WAIT_FOR manage";
+# Sending:
+SELECT * FROM t1;
+# Connection con2
+# Waiting for SELECT to be blocked by the metadata lock on t1
+SET DEBUG_SYNC= "now SIGNAL query";
+# Connection default
+# Reaping: ALTER TABLE t1 ADD PRIMARY KEY (a)
+# Connection con1
+# Reaping: SELECT * FROM t1
+a	b
+# Test 4: Secondary unique index, should not block reads.
+# Connection default
+SET DEBUG_SYNC= "RESET";
+DROP TABLE t1;

=== modified file 'mysql-test/t/innodb_mysql_sync.test'
--- a/mysql-test/t/innodb_mysql_sync.test	2011-01-10 13:12:23 +0000
+++ b/mysql-test/t/innodb_mysql_sync.test	2011-01-26 13:23:29 +0000
@@ -147,6 +147,139 @@ SET DEBUG_SYNC= 'RESET';
 disconnect con1;
 
 
+--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;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+connect(con1,localhost,root);
+connect(con2,localhost,root);
+
+--echo # Test 1: Secondary index, should not block reads (original test case).
+
+--echo # Connection default
+connection default;
+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";
+--echo # Sending:
+--send ALTER TABLE db1.t1 ADD INDEX(value)
+
+--echo # Connection con1
+connection con1;
+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";
+
+--echo # Connection default
+connection default;
+--echo # Reaping: ALTER TABLE db1.t1 ADD INDEX(value)
+--reap
+DROP DATABASE db1;
+
+--echo # Test 2: Primary index (implicit), should block reads.
+
+CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL) engine=innodb;
+SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query";
+--echo # Sending:
+--send ALTER TABLE t1 ADD UNIQUE INDEX(a)
+
+--echo # Connection con1
+connection con1;
+SET DEBUG_SYNC= "now WAIT_FOR manage";
+USE test;
+--echo # Sending:
+--send SELECT * FROM t1
+
+--echo # Connection con2
+connection con2;
+--echo # Waiting for SELECT to be blocked by the metadata lock on t1
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+  WHERE state= 'Waiting for table metadata lock'
+  AND info='SELECT * FROM t1';
+--source include/wait_condition.inc
+SET DEBUG_SYNC= "now SIGNAL query";
+
+--echo # Connection default
+connection default;
+--echo # Reaping: ALTER TABLE t1 ADD UNIQUE INDEX(a)
+--reap
+
+--echo # Connection con1
+connection con1;
+--echo # Reaping: SELECT * FROM t1
+--reap
+
+--echo # Test 3: Primary index (explicit), should block reads.
+
+--echo # Connection default
+connection default;
+ALTER TABLE t1 DROP INDEX a;
+SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query";
+--echo # Sending:
+--send ALTER TABLE t1 ADD PRIMARY KEY (a)
+
+--echo # Connection con1
+connection con1;
+SET DEBUG_SYNC= "now WAIT_FOR manage";
+--echo # Sending:
+--send SELECT * FROM t1
+
+--echo # Connection con2
+connection con2;
+--echo # Waiting for SELECT to be blocked by the metadata lock on t1
+let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
+  WHERE state= 'Waiting for table metadata lock'
+  AND info='SELECT * FROM t1';
+--source include/wait_condition.inc
+SET DEBUG_SYNC= "now SIGNAL query";
+
+--echo # Connection default
+connection default;
+--echo # Reaping: ALTER TABLE t1 ADD PRIMARY KEY (a)
+--reap
+
+--echo # Connection con1
+connection con1;
+--echo # Reaping: SELECT * FROM t1
+--reap
+
+--echo # Test 4: Secondary unique index, should not block reads.
+# This requires HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE to be supported
+# by InnoDB. Adding this flag currently introduces a regression so
+# this test is disabled until the regression has been fixed.
+
+--echo # Connection default
+connection default;
+#SET DEBUG_SYNC= "alter_table_manage_keys SIGNAL manage WAIT_FOR query";
+#--echo # Sending:
+#--send ALTER TABLE t1 ADD UNIQUE (b)
+
+#--echo # Connection con1
+#connection con1;
+#SET DEBUG_SYNC= "now WAIT_FOR manage";
+#SELECT * FROM t1;
+#SET DEBUG_SYNC= "now SIGNAL query";
+
+#--echo # Connection default
+#connection default;
+#--echo # Reaping: ALTER TABLE t1 ADD UNIQUE (b)
+#--reap
+
+disconnect con1;
+disconnect con2;
+SET DEBUG_SYNC= "RESET";
+DROP TABLE t1;
+
+
 # Check that all connections opened by test cases in this file are really
 # gone so execution of other tests won't be affected by their presence.
 --source include/wait_until_count_sessions.inc

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2010-12-17 20:58:40 +0000
+++ b/sql/ha_partition.cc	2011-01-26 13:23:29 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+/* Copyright (c) 2005, 2011, 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
@@ -6432,28 +6432,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	2011-01-26 13:23:29 +0000
@@ -1,7 +1,7 @@
 #ifndef HANDLER_INCLUDED
 #define HANDLER_INCLUDED
 
-/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+/* Copyright (c) 2000, 2011, 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
@@ -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*/
-/*
-  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).
-*/
-#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_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 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_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-22 14:08:51 +0000
+++ b/sql/sql_table.cc	2011-01-26 13:23:29 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+/* Copyright (c) 2000, 2011, 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
@@ -4745,7 +4745,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
@@ -4861,7 +4861,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);
@@ -4902,9 +4902,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.
   */
@@ -4927,7 +4927,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);
@@ -5207,7 +5207,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.
@@ -6102,7 +6102,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.
   */
@@ -6110,8 +6110,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_inplace_with_read_flags= 0;
+    ulong needed_inplace_flags= 0;
     KEY   *key;
     uint  *idx_p;
     uint  *idx_end_p;
@@ -6135,8 +6135,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_inplace_with_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--;
         }
@@ -6146,8 +6146,9 @@ 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_inplace_with_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
@@ -6166,12 +6167,13 @@ 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_inplace_with_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_inplace_with_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;
@@ -6209,57 +6211,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_inplace_with_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_inplace_with_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_inplace_with_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))
+    if ((candidate_key_count > 0) &&
+        (needed_inplace_with_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_inplace_with_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_inplace_with_read_flags: 0x%lx, needed_inplace_flags: 0x%lx",
+           needed_inplace_with_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_inplace_with_read_flags) ==
+          needed_inplace_with_read_flags)
       {
-        /* All required online flags are present. */
+        /* All required in-place 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;
       }
     }
@@ -6413,10 +6417,18 @@ bool mysql_alter_table(THD *thd,char *ne
   }
   else
   {
-    if (!table->s->tmp_table &&
+    /*
+      Ensure that we will upgrade the metadata lock if
+      handler::enable/disable_indexes() will be called.
+    */
+    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	2011-01-07 11:54:07 +0000
+++ b/storage/innobase/handler/ha_innodb.cc	2011-01-26 13:23:29 +0000
@@ -2574,11 +2574,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);
 }
 
 /*****************************************************************//**

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.5 branch (jon.hauglid:3277 to 3278) Bug#42230Jon Olav Hauglid26 Jan