List:Commits« Previous MessageNext Message »
From:marko.makela Date:May 30 2012 7:57pm
Subject:bzr push into mysql-trunk-wl6255 branch (marko.makela:3909 to 3911) WL#6255
View as plain text  
 3911 Marko Mäkelä	2012-05-30
      WL#6255 MVCC bug fix: Ensure that older transactions are denied access
      to a table that has been rebuilt, whether or not it happened in-place
      (ALGORITHM=INPLACE) or in the old way (ALGORITHM=COPY).
      
      When a table is created, we record the trx_id of the creating data
      dictionary transaction in each index of the table in the data dictionary
      cache. In this way, transactions that were started before the table
      creation (or copying) can be denied access to the new table.
      
      To be exact, there are two transactions involved in DDL. One is the
      user transaction associated with the MySQL client connection. For
      InnoDB data dictionary operations, we create a data dictionary transaction.
      Theoretically, other transactions could start between the prebuilt->trx
      and the dictionary trx. However, the table cannot be modified during this
      time frame, thanks to a meta-data lock (MDL). In CREATE TABLE, the table
      does not exist before InnoDB returns, and in ALTER TABLE, other transactions
      are blocked from accessing the table while the table copy is being set up.
      
      dict_create_index_step(): Initialize index->trx_id, so that older
      transactions will be denied access to a newly created table.
      
      ha_innobase::commit_inplace_alter_table(): Remove the adjustment of
      index->trx_id for ALGORITHM=INPLACE.

    modified:
      mysql-test/suite/innodb/r/innodb-index.result
      mysql-test/suite/innodb/t/innodb-index.test
      storage/innobase/dict/dict0crea.cc
      storage/innobase/handler/handler0alter.cc
 3910 Marko Mäkelä	2012-05-30
      WL#6255 bug fix: Relax a bogus debug assertion.
      
      btr_page_split_and_insert(): This function can be invoked during
      online secondary index creation when loading the created index.

    modified:
      storage/innobase/btr/btr0btr.cc
 3909 Marko Mäkelä	2012-05-30
      WL#6255: Fix the online rebuild logging of ROW_FORMAT=REDUNDANT tables.
      
      Move some accessor function prototypes and #defines from rem0rec.ic
      to rem0rec.h.
      
      rec_2_is_field_extern(): Determine if a field is stored externally.
      
      row_log_table_low_redundant(): Like row_log_table_low(), but for
      ROW_FORMAT=REDUNDANT records. Convert the rec_t to a dtuple_t and
      then to the rebuild log format. Add some assertions.

    modified:
      storage/innobase/include/rem0rec.h
      storage/innobase/include/rem0rec.ic
      storage/innobase/row/row0log.cc
=== modified file 'mysql-test/suite/innodb/r/innodb-index.result'
--- a/mysql-test/suite/innodb/r/innodb-index.result	revid:marko.makela@stripped530125444-m89sg202qswa44h4
+++ b/mysql-test/suite/innodb/r/innodb-index.result	revid:marko.makela@stripped530194837-18ttnm2mooe7dl2p
@@ -925,7 +925,11 @@ DROP TABLE t1;
 CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB;
 INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e');
 CREATE TABLE t2 (a INT, b CHAR(1)) ENGINE=InnoDB;
+CREATE TABLE t2i (a INT NOT NULL, b CHAR(1) NOT NULL) ENGINE=InnoDB;
+CREATE TABLE t2c (a INT NOT NULL, b CHAR(1) NOT NULL) ENGINE=InnoDB;
 INSERT INTO t2 SELECT * FROM t1;
+INSERT INTO t2i SELECT * FROM t1;
+INSERT INTO t2c SELECT * FROM t1;
 BEGIN;
 SELECT * FROM t1;
 a	b
@@ -937,7 +941,19 @@ a	b
 SET lock_wait_timeout=1;
 CREATE INDEX t1a ON t1(a);
 ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+ALTER TABLE t2 ADD PRIMARY KEY(a,b), ADD INDEX t2a(a), ALGORITHM=INPLACE;
+ERROR 42000: This version of MySQL doesn't yet support 'ALTER TABLE t2 ADD PRIMARY KEY(a,b), ADD INDEX t2a(a), ALGORITHM=INPLACE'
 CREATE INDEX t2a ON t2(a);
+ALTER TABLE t2i ADD PRIMARY KEY(a,b), ADD INDEX t2a(a), ALGORITHM=INPLACE;
+ALTER TABLE t2c ADD PRIMARY KEY(a,b), ADD INDEX t2a(a), ALGORITHM=COPY;
+SELECT * FROM t2i;
+ERROR HY000: Table definition has changed, please retry transaction
+SELECT * FROM t2i FORCE INDEX(t2a) ORDER BY a;
+ERROR HY000: Table definition has changed, please retry transaction
+SELECT * FROM t2c;
+ERROR HY000: Table definition has changed, please retry transaction
+SELECT * FROM t2c FORCE INDEX(t2a) ORDER BY a;
+ERROR HY000: Table definition has changed, please retry transaction
 SELECT * FROM t2;
 a	b
 3	a
@@ -955,6 +971,13 @@ a	b
 0	d
 1	e
 COMMIT;
+SELECT * FROM t2;
+a	b
+3	a
+3	b
+1	c
+0	d
+1	e
 SELECT * FROM t2 FORCE INDEX(t2a) ORDER BY a;
 a	b
 0	d
@@ -962,6 +985,34 @@ a	b
 1	e
 3	a
 3	b
+SELECT * FROM t2i;
+a	b
+0	d
+1	c
+1	e
+3	a
+3	b
+SELECT * FROM t2i FORCE INDEX(t2a) ORDER BY a;
+a	b
+0	d
+1	c
+1	e
+3	a
+3	b
+SELECT * FROM t2c;
+a	b
+0	d
+1	c
+1	e
+3	a
+3	b
+SELECT * FROM t2c FORCE INDEX(t2a) ORDER BY a;
+a	b
+0	d
+1	c
+1	e
+3	a
+3	b
 alter table t2 add index t2a(b);
 ERROR 42000: Duplicate key name 't2a'
 alter table t2 drop index t2a, add index t2a(b);
@@ -972,4 +1023,20 @@ t2	CREATE TABLE `t2` (
   `b` char(1) DEFAULT NULL,
   KEY `t2a` (`b`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
-DROP TABLE t1,t2;
+show create table t2i;
+Table	Create Table
+t2i	CREATE TABLE `t2i` (
+  `a` int(11) NOT NULL,
+  `b` char(1) NOT NULL,
+  PRIMARY KEY (`a`,`b`),
+  KEY `t2a` (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+show create table t2c;
+Table	Create Table
+t2c	CREATE TABLE `t2c` (
+  `a` int(11) NOT NULL,
+  `b` char(1) NOT NULL,
+  PRIMARY KEY (`a`,`b`),
+  KEY `t2a` (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1,t2,t2c,t2i;

=== modified file 'mysql-test/suite/innodb/t/innodb-index.test'
--- a/mysql-test/suite/innodb/t/innodb-index.test	revid:marko.makela@stripped4-m89sg202qswa44h4
+++ b/mysql-test/suite/innodb/t/innodb-index.test	revid:marko.makela@stripped18ttnm2mooe7dl2p
@@ -348,7 +348,11 @@ connection a;
 CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB;
 INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e');
 CREATE TABLE t2 (a INT, b CHAR(1)) ENGINE=InnoDB;
+CREATE TABLE t2i (a INT NOT NULL, b CHAR(1) NOT NULL) ENGINE=InnoDB;
+CREATE TABLE t2c (a INT NOT NULL, b CHAR(1) NOT NULL) ENGINE=InnoDB;
 INSERT INTO t2 SELECT * FROM t1;
+INSERT INTO t2i SELECT * FROM t1;
+INSERT INTO t2c SELECT * FROM t1;
 connection b;
 BEGIN;
 # This acquires a MDL lock on t1 until commit.
@@ -358,14 +362,35 @@ connection a;
 SET lock_wait_timeout=1;
 --error ER_LOCK_WAIT_TIMEOUT
 CREATE INDEX t1a ON t1(a);
+# InnoDB cannot change a column to NOT NULL yet
+--error ER_NOT_SUPPORTED_YET
+ALTER TABLE t2 ADD PRIMARY KEY(a,b), ADD INDEX t2a(a), ALGORITHM=INPLACE;
 CREATE INDEX t2a ON t2(a);
+ALTER TABLE t2i ADD PRIMARY KEY(a,b), ADD INDEX t2a(a), ALGORITHM=INPLACE;
+ALTER TABLE t2c ADD PRIMARY KEY(a,b), ADD INDEX t2a(a), ALGORITHM=COPY;
 connection b;
+# t2i and t2c are too new for this transaction, because they were rebuilt
+--error ER_TABLE_DEF_CHANGED
+SELECT * FROM t2i;
+--error ER_TABLE_DEF_CHANGED
+SELECT * FROM t2i FORCE INDEX(t2a) ORDER BY a;
+--error ER_TABLE_DEF_CHANGED
+SELECT * FROM t2c;
+--error ER_TABLE_DEF_CHANGED
+SELECT * FROM t2c FORCE INDEX(t2a) ORDER BY a;
+# In t2, only the new index t2a is too new for this transaction.
 SELECT * FROM t2;
 --error ER_TABLE_DEF_CHANGED
 SELECT * FROM t2 FORCE INDEX(t2a) ORDER BY a;
 SELECT * FROM t2;
 COMMIT;
+# For a new transaction, all of t2, t2i, t2c are accessible.
+SELECT * FROM t2;
 SELECT * FROM t2 FORCE INDEX(t2a) ORDER BY a;
+SELECT * FROM t2i;
+SELECT * FROM t2i FORCE INDEX(t2a) ORDER BY a;
+SELECT * FROM t2c;
+SELECT * FROM t2c FORCE INDEX(t2a) ORDER BY a;
 connection default;
 disconnect a;
 disconnect b;
@@ -374,5 +399,7 @@ disconnect b;
 alter table t2 add index t2a(b);
 alter table t2 drop index t2a, add index t2a(b);
 show create table t2;
+show create table t2i;
+show create table t2c;
 
-DROP TABLE t1,t2;
+DROP TABLE t1,t2,t2c,t2i;

=== modified file 'storage/innobase/btr/btr0btr.cc'
--- a/storage/innobase/btr/btr0btr.cc	revid:marko.makela@stripped4
+++ b/storage/innobase/btr/btr0btr.cc	revid:marko.makela@stripped
@@ -2599,6 +2599,7 @@ func_start:
 	ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index),
 				MTR_MEMO_X_LOCK));
 	ut_ad(!dict_index_is_online_ddl(cursor->index)
+	      || (flags & BTR_CREATE_FLAG)
 	      || dict_index_is_clust(cursor->index));
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(rw_lock_own(dict_index_get_lock(cursor->index), RW_LOCK_EX));

=== modified file 'storage/innobase/dict/dict0crea.cc'
--- a/storage/innobase/dict/dict0crea.cc	revid:marko.makela@oracle.com-20120530125444-m89sg202qswa44h4
+++ b/storage/innobase/dict/dict0crea.cc	revid:marko.makela@stripped-20120530194837-18ttnm2mooe7dl2p
@@ -1167,6 +1167,7 @@ dict_create_index_step(
 		}
 
 		node->index->page = node->page_no;
+		node->index->trx_id = trx->id;
 		node->state = INDEX_COMMIT_WORK;
 	}
 

=== modified file 'storage/innobase/handler/handler0alter.cc'
--- a/storage/innobase/handler/handler0alter.cc	revid:marko.makela@stripped0120530125444-m89sg202qswa44h4
+++ b/storage/innobase/handler/handler0alter.cc	revid:marko.makela@stripped530194837-18ttnm2mooe7dl2p
@@ -3039,22 +3039,13 @@ ha_innobase::commit_inplace_alter_table(
 
 		switch (error) {
 			dict_table_t*	old_table;
-			trx_id_t	trx_id;
 		case DB_SUCCESS:
 			old_table = prebuilt->table;
-			trx_id = prebuilt->trx->id;
 			trx_commit_for_mysql(prebuilt->trx);
 			row_prebuilt_free(prebuilt, TRUE);
 			error = row_merge_drop_table(trx, old_table);
 			prebuilt = row_create_prebuilt(
 				ctx->indexed_table, table->s->reclength);
-			/* Prevent old transactions from accessing the
-			rebuilt table, because the history is missing. */
-			for (dict_index_t* index = dict_table_get_first_index(
-				     ctx->indexed_table);
-			     index; index = dict_table_get_next_index(index)) {
-				index->trx_id = trx_id;
-			}
 			err = 0;
 			break;
 		case DB_TABLESPACE_ALREADY_EXISTS:

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-wl6255 branch (marko.makela:3909 to 3911) WL#6255marko.makela30 May