# At a local mysql-6.0 repository of davi
2743 Davi Arnaut 2009-03-06
Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
WL#4284: Transactional DDL locking
Currently the MySQL server does not keep metadata locks on
schema objects for the duration of a transaction, thus failing
to guarantee the integrity of the schema objects being used
during the transaction and to protect then from concurrent
DDL operations. This also poses a problem for replication as
a DDL operation might be replicated even thought there are
active transactions using the object being modified.
The solution is to defer the release of metadata locks until
a active transaction is either committed or rolled back. This
prevents other statements from modifying the table for the
entire duration of the transaction. This provides commitment
ordering for guaranteeing serializability across multiple
transactions.
- Incompatible change:
If MySQL's metadata locking system encounters a lock conflict,
the usual schema is to use the try and back-off technique to
avoid deadlocks -- this schema consists in releasing all locks
and trying to acquire them all in one go.
But in a transactional context this algorithm can't be utilized
as its not possible to release locks acquired during the course
of the transaction without breaking the transaction commitments.
To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be
returned if a lock conflict is encountered during a transaction.
Let's consider an example:
A transaction has two statements that modify table t1, then table
t2, and then commits. The first statement of the transaction will
acquire a shared metadata lock on table t1, and it will be kept
utill COMMIT to ensure serializability.
At the moment when the second statement attempts to acquire a
shared metadata lock on t2, a concurrent ALTER or DROP statement
might have locked t2 exclusively. The prescription of the current
locking protocol is that the acquirer of the shared lock backs off
-- gives up all his current locks and retries. This implies that
the entire multi-statement transaction has to be rolled back.
- Incompatible change:
FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ
LOCK won't cause locked tables to be implicitly unlocked anymore.
@ mysql-test/extra/binlog_tests/drop_table.test
Add test case for Bug#989
@ mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/include/locktrans.inc
Add test case for WL#4284
@ mysql-test/include/mix1.inc
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/include/mix2.inc
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/r/flush_block_commit.result
Update test case result.
@ mysql-test/r/flush_block_commit_notembedded.result
Update test case result.
@ mysql-test/r/innodb.result
Update test case result.
@ mysql-test/r/innodb_mysql.result
Update test case result.
@ mysql-test/r/lock.result
Add test case result.
@ mysql-test/r/locktrans_innodb.result
Add test case result for WL#4284
@ mysql-test/r/locktrans_myisam.result
Add test case result for WL#4284
@ mysql-test/r/mix2_myisam.result
Update test case result.
@ mysql-test/r/partition_innodb_semi_consistent.result
Update test case result.
@ mysql-test/r/read_only_innodb.result
Update test case result.
@ mysql-test/suite/binlog/r/binlog_row_drop_tbl.result
Add test case result for Bug#989
@ mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
Update test case result.
@ mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result
Add test case result for Bug#989
@ mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
Update test case result.
@ mysql-test/suite/binlog/t/binlog_row_drop_tbl.test
Add test case for Bug#989
@ mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test
Add test case for Bug#989
@ mysql-test/suite/falcon/r/falcon_bugs2.result
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/suite/falcon/t/disabled.def
Disable tests made meaningless by transactional metadata locking.
@ mysql-test/suite/falcon/t/falcon_bugs2.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/suite/ndb/r/ndb_index_ordered.result
Remove result for disabled part of the test case.
@ mysql-test/suite/ndb/t/disabled.def
Disable tests made meaningless by transactional metadata locking.
@ mysql-test/suite/ndb/t/ndb_index_ordered.test
Comment out test made meaningless by transactional metadata locking.
@ mysql-test/suite/rpl/r/rpl_locktrans_falcon.result
Add test case result for WL#4284
@ mysql-test/suite/rpl/r/rpl_locktrans_innodb.result
Add test case result for WL#4284
@ mysql-test/suite/rpl/r/rpl_locktrans_myisam.result
Add test case result for WL#4284
@ mysql-test/suite/rpl/t/disabled.def
Disable tests made meaningless by transactional metadata locking.
@ mysql-test/suite/sys_vars/t/autocommit_func.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/t/flush_block_commit.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/t/flush_block_commit_notembedded.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/t/innodb.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/t/partition_innodb_semi_consistent.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/t/read_only_innodb.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ mysql-test/t/xa.test
Fix test case to reflect the fact that transactions now hold
metadata locks for the duration of a transaction.
@ sql/log_event.cc
Release metadata locks after issuing a commit.
@ sql/mysql_priv.h
Rename parameter to match the name used in the definition.
@ sql/rpl_injector.cc
Release metadata locks on commit and rollback.
@ sql/rpl_rli.cc
Remove assert made meaningless, metadata locks are released
at the end of the transaction.
@ sql/set_var.cc
Close tables and release locks if autocommit mode is set.
@ sql/slave.cc
Release metadata locks after a rollback.
@ sql/sql_acl.cc
Don't implicitly unlock locked tables. Issue a implicit commit
at the end and unlock tables.
@ sql/sql_base.cc
Defer the release of metadata locks when closing tables
if not required to.
Issue a deadlock error if the locking protocol requires
that a transaction re-acquire its locks.
Release metadata locks when closing tables for reopen.
@ sql/sql_class.cc
Release metadata locks if the thread is killed.
@ sql/sql_parse.cc
Release metadata locks after implicitly committing a active
transaction, or after explicit commits or rollbacks.
@ sql/sql_servers.cc
Don't implicitly unlock locked tables. Issue a implicit commit
at the end and unlock tables.
@ sql/sql_table.cc
Close table and release metadata locks after a admin operation.
@ sql/transaction.cc
Release metadata locks after the implicitly committed due
to a new transaction being started. Also, release metadata
locks acquired after a savepoint if the transaction is rolled
back to the save point.
added:
mysql-test/extra/binlog_tests/drop_table.test
mysql-test/suite/binlog/r/binlog_row_drop_tbl.result
mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result
mysql-test/suite/binlog/t/binlog_row_drop_tbl.test
mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test
modified:
mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
mysql-test/include/locktrans.inc
mysql-test/include/mix1.inc
mysql-test/include/mix2.inc
mysql-test/r/flush_block_commit.result
mysql-test/r/flush_block_commit_notembedded.result
mysql-test/r/innodb.result
mysql-test/r/innodb_mysql.result
mysql-test/r/lock.result
mysql-test/r/locktrans_innodb.result
mysql-test/r/locktrans_myisam.result
mysql-test/r/mix2_myisam.result
mysql-test/r/partition_innodb_semi_consistent.result
mysql-test/r/read_only_innodb.result
mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
mysql-test/suite/falcon/r/falcon_bugs2.result
mysql-test/suite/falcon/t/disabled.def
mysql-test/suite/falcon/t/falcon_bugs2.test
mysql-test/suite/ndb/r/ndb_index_ordered.result
mysql-test/suite/ndb/t/disabled.def
mysql-test/suite/ndb/t/ndb_index_ordered.test
mysql-test/suite/rpl/r/rpl_locktrans_falcon.result
mysql-test/suite/rpl/r/rpl_locktrans_innodb.result
mysql-test/suite/rpl/r/rpl_locktrans_myisam.result
mysql-test/suite/rpl/t/disabled.def
mysql-test/suite/sys_vars/t/autocommit_func.test
mysql-test/t/flush_block_commit.test
mysql-test/t/flush_block_commit_notembedded.test
mysql-test/t/innodb.test
mysql-test/t/lock.test
mysql-test/t/partition_innodb_semi_consistent.test
mysql-test/t/read_only_innodb.test
mysql-test/t/xa.test
sql/log_event.cc
sql/mysql_priv.h
sql/rpl_injector.cc
sql/rpl_rli.cc
sql/set_var.cc
sql/slave.cc
sql/sql_acl.cc
sql/sql_base.cc
sql/sql_class.cc
sql/sql_parse.cc
sql/sql_servers.cc
sql/sql_table.cc
sql/transaction.cc
=== added file 'mysql-test/extra/binlog_tests/drop_table.test'
--- a/mysql-test/extra/binlog_tests/drop_table.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/extra/binlog_tests/drop_table.test 2009-03-06 22:17:00 +0000
@@ -0,0 +1,34 @@
+#
+# Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+
+connection con1;
+RESET MASTER;
+CREATE TABLE t1 (a INT);
+SET AUTOCOMMIT=OFF;
+BEGIN;
+INSERT INTO t1 VALUES(1);
+
+connection con2;
+--send DROP TABLE t1;
+
+connection con1;
+COMMIT;
+
+connection con2;
+--reap
+
+connection default;
+
+--disconnect con1
+--disconnect con2
+
+let $VERSION=`select version()`;
+source include/show_binlog_events.inc;
=== modified file 'mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test'
--- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test 2008-07-22 14:16:22
+0000
+++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test 2009-03-06 22:17:00
+0000
@@ -204,6 +204,10 @@ select (@after:=unix_timestamp())*0; # a
# the bug, the reap would return immediately after the insert into t2.
select (@after-@before) >= 2;
+connection con3;
+commit;
+
+connection con2;
drop table t1,t2;
commit;
=== modified file 'mysql-test/include/locktrans.inc'
--- a/mysql-test/include/locktrans.inc 2008-05-23 13:54:03 +0000
+++ b/mysql-test/include/locktrans.inc 2009-03-06 22:17:00 +0000
@@ -1050,6 +1050,19 @@ COMMIT;
DROP TRIGGER t1_ai;
}
+--echo #
+--echo # WL#4284: Transactional DDL locking
+--echo #
+
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
+
#
--echo ## Cleanup.
connection default;
=== modified file 'mysql-test/include/mix1.inc'
--- a/mysql-test/include/mix1.inc 2009-02-02 15:58:48 +0000
+++ b/mysql-test/include/mix1.inc 2009-03-06 22:17:00 +0000
@@ -1331,6 +1331,7 @@ SELECT * FROM t1;
connection con2;
--reap
SELECT * FROM t1;
+COMMIT;
--echo # Switch to connection con1
connection con1;
=== modified file 'mysql-test/include/mix2.inc'
--- a/mysql-test/include/mix2.inc 2007-06-06 17:57:07 +0000
+++ b/mysql-test/include/mix2.inc 2009-03-06 22:17:00 +0000
@@ -1994,6 +1994,7 @@ commit;
connection b;
set autocommit = 0;
update t1 set b = 5 where a = 2;
+commit;
connection a;
delimiter |;
create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5,
NEW.c = NEW.a / 10; end |
@@ -2056,6 +2057,7 @@ update t2 set b = b + 5 where a = 1;
update t3 set b = b + 5 where a = 1;
update t4 set b = b + 5 where a = 1;
insert into t5(a) values(20);
+commit;
connection b;
set autocommit = 0;
insert into t1(a) values(7);
=== modified file 'mysql-test/r/flush_block_commit.result'
--- a/mysql-test/r/flush_block_commit.result 2006-12-26 16:22:17 +0000
+++ b/mysql-test/r/flush_block_commit.result 2009-03-06 22:17:00 +0000
@@ -2,12 +2,11 @@ drop table if exists t1;
create table t1 (a int) engine=innodb;
begin;
insert into t1 values(1);
-flush tables with read lock;
-select * from t1;
-a
+flush tables with read lock;;
commit;
select * from t1;
a
+1
unlock tables;
begin;
select * from t1 for update;
@@ -19,13 +18,12 @@ flush tables with read lock;
commit;
a
1
+commit;
unlock tables;
commit;
begin;
insert into t1 values(10);
flush tables with read lock;
-commit;
-unlock tables;
flush tables with read lock;
unlock tables;
begin;
@@ -36,4 +34,10 @@ a
show create database test;
Database Create Database
test CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */
+commit;
+flush tables with read lock;
+begin;
+insert into t1 values (1);;
+unlock tables;
+commit;
drop table t1;
=== modified file 'mysql-test/r/flush_block_commit_notembedded.result'
--- a/mysql-test/r/flush_block_commit_notembedded.result 2008-02-03 09:00:49 +0000
+++ b/mysql-test/r/flush_block_commit_notembedded.result 2009-03-06 22:17:00 +0000
@@ -1,12 +1,14 @@
create table t1 (a int) engine=innodb;
reset master;
set autocommit=0;
-insert t1 values (1);
+select 1;
+1
+1
flush tables with read lock;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 107
-commit;
+insert into t1 values (1);
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 107
=== modified file 'mysql-test/r/innodb.result'
--- a/mysql-test/r/innodb.result 2009-02-13 16:30:54 +0000
+++ b/mysql-test/r/innodb.result 2009-03-06 22:17:00 +0000
@@ -2819,10 +2819,10 @@ t2 CREATE TABLE `t2` (
DROP TABLE t2,t1;
create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
insert into t1(a) values (1),(2),(3);
+create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5,
NEW.c = NEW.a / 10; end |
commit;
set autocommit = 0;
update t1 set b = 5 where a = 2;
-create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5,
NEW.c = NEW.a / 10; end |
set autocommit = 0;
insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100),
(11),(21),(31),(41),(51),(61),(71),(81),(91),(101),
@@ -2870,6 +2870,7 @@ insert into t2(a) values(8);
delete from t2 where a = 3;
update t4 set b = b + 1 where a = 3;
commit;
+commit;
drop trigger t1t;
drop trigger t2t;
drop trigger t3t;
=== modified file 'mysql-test/r/innodb_mysql.result'
--- a/mysql-test/r/innodb_mysql.result 2009-02-12 18:27:05 +0000
+++ b/mysql-test/r/innodb_mysql.result 2009-03-06 22:17:00 +0000
@@ -1564,6 +1564,7 @@ a b
SELECT * FROM t1;
a b
1 init+con1+con2
+COMMIT;
# Switch to connection con1
# 3. test for updated key column:
TRUNCATE t1;
=== modified file 'mysql-test/r/lock.result'
--- a/mysql-test/r/lock.result 2008-10-21 23:12:53 +0000
+++ b/mysql-test/r/lock.result 2009-03-06 22:17:00 +0000
@@ -235,5 +235,17 @@ unlock tables;
drop table t1;
drop view v1;
#
+# WL#4284: Transactional DDL locking
+#
+# FLUSH PRIVILEGES should not implicitly unlock locked tables.
+#
+drop table if exists t1;
+create table t1 (c1 int);
+lock tables t1 read;
+flush privileges;
+ERROR HY000: Table 'host' was not locked with LOCK TABLES
+unlock tables;
+drop table t1;
+#
# End of 6.0 tests.
#
=== modified file 'mysql-test/r/locktrans_innodb.result'
--- a/mysql-test/r/locktrans_innodb.result 2008-12-24 10:48:24 +0000
+++ b/mysql-test/r/locktrans_innodb.result 2009-03-06 22:17:00 +0000
@@ -920,6 +920,17 @@ TRUNCATE t1;
TRUNCATE t2;
COMMIT;
DROP TRIGGER t1_ai;
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
## Cleanup.
SET AUTOCOMMIT= 1;
UNLOCK TABLES;
=== modified file 'mysql-test/r/locktrans_myisam.result'
--- a/mysql-test/r/locktrans_myisam.result 2008-12-24 10:48:24 +0000
+++ b/mysql-test/r/locktrans_myisam.result 2009-03-06 22:17:00 +0000
@@ -392,6 +392,19 @@ ERROR 0A000: LOCK is not allowed in stor
CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW
LOCK TABLE t2 IN EXCLUSIVE MODE;
ERROR 0A000: LOCK is not allowed in stored procedures
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+UNLOCK TABLES;
## Cleanup.
SET AUTOCOMMIT= 1;
UNLOCK TABLES;
=== modified file 'mysql-test/r/mix2_myisam.result'
--- a/mysql-test/r/mix2_myisam.result 2008-10-20 09:16:47 +0000
+++ b/mysql-test/r/mix2_myisam.result 2009-03-06 22:17:00 +0000
@@ -2063,6 +2063,7 @@ insert into t1(a) values (1),(2),(3);
commit;
set autocommit = 0;
update t1 set b = 5 where a = 2;
+commit;
create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5,
NEW.c = NEW.a / 10; end |
set autocommit = 0;
insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100),
@@ -2105,6 +2106,7 @@ update t2 set b = b + 5 where a = 1;
update t3 set b = b + 5 where a = 1;
update t4 set b = b + 5 where a = 1;
insert into t5(a) values(20);
+commit;
set autocommit = 0;
insert into t1(a) values(7);
insert into t2(a) values(8);
=== modified file 'mysql-test/r/partition_innodb_semi_consistent.result'
--- a/mysql-test/r/partition_innodb_semi_consistent.result 2009-01-13 22:12:16 +0000
+++ b/mysql-test/r/partition_innodb_semi_consistent.result 2009-03-06 22:17:00 +0000
@@ -102,7 +102,7 @@ a b
# Switch to connection con1
# 3. test for updated key column:
TRUNCATE t1;
-TRUNCATE t2;
+DELETE FROM t2;
INSERT INTO t1 VALUES (1,'init');
BEGIN;
UPDATE t1 SET a = 2, b = CONCAT(b, '+con1') WHERE a = 1;
=== modified file 'mysql-test/r/read_only_innodb.result'
--- a/mysql-test/r/read_only_innodb.result 2008-04-08 05:20:58 +0000
+++ b/mysql-test/r/read_only_innodb.result 2009-03-06 22:17:00 +0000
@@ -7,12 +7,10 @@ insert into table_11733 values(11733);
set global read_only=1;
select @@global.read_only;
@@global.read_only
-1
+0
select * from table_11733 ;
-a
-11733
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
-ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute
this statement
set global read_only=0;
drop table table_11733 ;
drop user test@localhost;
=== added file 'mysql-test/suite/binlog/r/binlog_row_drop_tbl.result'
--- a/mysql-test/suite/binlog/r/binlog_row_drop_tbl.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_drop_tbl.result 2009-03-06 22:17:00 +0000
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS t1;
+RESET MASTER;
+CREATE TABLE t1 (a INT);
+SET AUTOCOMMIT=OFF;
+BEGIN;
+INSERT INTO t1 VALUES(1);
+DROP TABLE t1;;
+COMMIT;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT)
+master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # use `test`; DROP TABLE t1
=== modified file 'mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result'
--- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result 2009-02-10 14:46:07
+0000
+++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result 2009-03-06 22:17:00
+0000
@@ -232,6 +232,7 @@ select (@after:=unix_timestamp())*0;
select (@after-@before) >= 2;
(@after-@before) >= 2
1
+commit;
drop table t1,t2;
commit;
begin;
@@ -272,6 +273,10 @@ master-bin.000001 # Query # # use `test`
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t2)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # use `test`; COMMIT
master-bin.000001 # Query # # use `test`; drop table t1,t2
master-bin.000001 # Query # # use `test`; create table t0 (n int)
master-bin.000001 # Query # # use `test`; BEGIN
=== added file 'mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result 2009-03-06 22:17:00 +0000
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS t1;
+RESET MASTER;
+CREATE TABLE t1 (a INT);
+SET AUTOCOMMIT=OFF;
+BEGIN;
+INSERT INTO t1 VALUES(1);
+DROP TABLE t1;;
+COMMIT;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT)
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES(1)
+master-bin.000001 # Query # # use `test`; DROP TABLE t1
=== modified file 'mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result 2009-02-10 14:46:07
+0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result 2009-03-06 22:17:00
+0000
@@ -207,6 +207,7 @@ select (@after:=unix_timestamp())*0;
select (@after-@before) >= 2;
(@after-@before) >= 2
1
+commit;
drop table t1,t2;
commit;
begin;
=== added file 'mysql-test/suite/binlog/t/binlog_row_drop_tbl.test'
--- a/mysql-test/suite/binlog/t/binlog_row_drop_tbl.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_row_drop_tbl.test 2009-03-06 22:17:00 +0000
@@ -0,0 +1,5 @@
+# This is a wrapper for drop_table.test so that the same test case can be used
+# For both statement and row based bin logs
+
+-- source include/have_binlog_format_row.inc
+-- source extra/binlog_tests/drop_table.test
=== added file 'mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test'
--- a/mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test 2009-03-06 22:17:00 +0000
@@ -0,0 +1,5 @@
+# This is a wrapper for drop_table.test so that the same test case can be used
+# For both statement and row based bin logs
+
+-- source include/have_binlog_format_mixed_or_statement.inc
+-- source extra/binlog_tests/drop_table.test
=== modified file 'mysql-test/suite/falcon/r/falcon_bugs2.result'
--- a/mysql-test/suite/falcon/r/falcon_bugs2.result 2007-09-20 15:44:25 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bugs2.result 2009-03-06 22:17:00 +0000
@@ -290,6 +290,7 @@ SET autocommit=0;
SELECT * FROM t1;
a
DROP TABLE t1;
+COMMIT;
***************** falcon_bugs2_022 *****************
SET autocommit=0;
SET tx_isolation="READ-COMMITTED";
@@ -306,6 +307,8 @@ a
SELECT * FROM t1;
a
1
+COMMIT;
+COMMIT;
DROP TABLE t1;
***************** falcon_bugs2_023 *****************
CREATE TABLE t1 (a int);
=== modified file 'mysql-test/suite/falcon/t/disabled.def'
--- a/mysql-test/suite/falcon/t/disabled.def 2009-02-25 13:15:43 +0000
+++ b/mysql-test/suite/falcon/t/disabled.def 2009-03-06 22:17:00 +0000
@@ -11,3 +11,5 @@
##############################################################################
falcon_unicode-big : Bug#43182 2009-02-25 hakank Disabled until licensing details of
UnicodeData.txt are cleared
+falcon_bug_22972 : WL#4284: Can't drop table used by a pending transaction (there is
metadata lock on the table).
+falcon_bug_24024 : WL#4284: Can't drop table used by a pending transaction (there is
metadata lock on the table).
=== modified file 'mysql-test/suite/falcon/t/falcon_bugs2.test'
--- a/mysql-test/suite/falcon/t/falcon_bugs2.test 2009-01-07 10:41:07 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bugs2.test 2009-03-06 22:17:00 +0000
@@ -512,7 +512,11 @@ SELECT * FROM t1;
# Final cleanup
connection default;
-DROP TABLE t1;
+send DROP TABLE t1;
+connection con1;
+COMMIT;
+connection default;
+--reap
--disconnect con1
#
@@ -539,6 +543,10 @@ SELECT * FROM t1;
connection con1;
SELECT * FROM t1;
+COMMIT;
+
+connection default;
+COMMIT;
# Final cleanup
DROP TABLE t1;
=== modified file 'mysql-test/suite/ndb/r/ndb_index_ordered.result'
--- a/mysql-test/suite/ndb/r/ndb_index_ordered.result 2007-06-27 12:28:02 +0000
+++ b/mysql-test/suite/ndb/r/ndb_index_ordered.result 2009-03-06 22:17:00 +0000
@@ -637,21 +637,6 @@ select count(*)- 4 from t1 use index (v)
count(*)- 4
0
drop table t1;
-create table t1(a int primary key, b int not null, index(b));
-insert into t1 values (1,1), (2,2);
-set autocommit=0;
-begin;
-select count(*) from t1;
-count(*)
-2
-ALTER TABLE t1 ADD COLUMN c int;
-select a from t1 where b = 2;
-a
-2
-show tables;
-Tables_in_test
-t1
-drop table t1;
create table t1 (a int, c varchar(10),
primary key using hash (a), index(c)) engine=ndb;
insert into t1 (a, c) values (1,'aaa'),(3,'bbb');
=== modified file 'mysql-test/suite/ndb/t/disabled.def'
--- a/mysql-test/suite/ndb/t/disabled.def 2009-02-13 16:18:07 +0000
+++ b/mysql-test/suite/ndb/t/disabled.def 2009-03-06 22:17:00 +0000
@@ -14,3 +14,5 @@ ndb_partition_error2 : Bug#40989 msven
# the below testcase have been reworked to avoid the bug, test contains comment, keep bug
open
#ndb_binlog_ddl_multi : BUG#18976 2006-04-10 kent CRBR: multiple binlog, second
binlog may miss schema log events
ndb_cache_trans : Bug#42565 ndb_cache_trans failure since
SERVER_STATUS_IN_TRANS added to hash key
+ndb_alter_table_online : WL#4284: Needs to be reworked, tries to alter table used by a
pending transaction.
+ndb_alter_table3 : WL#4284: Needs to be reworked, tries to alter table used by a
pending transaction.
=== modified file 'mysql-test/suite/ndb/t/ndb_index_ordered.test'
--- a/mysql-test/suite/ndb/t/ndb_index_ordered.test 2007-07-04 20:38:53 +0000
+++ b/mysql-test/suite/ndb/t/ndb_index_ordered.test 2009-03-06 22:17:00 +0000
@@ -333,21 +333,29 @@ select count(*)- 4 from t1 use index (v)
drop table t1;
+#
+# Disabled due to WL#4284
+#
+# Needs to be reworked. It's not possible anymore to do a non-fast alter table
+# on a table that is being used by a pending transaction (transaction holds a
+# metadata lock on the table).
+#
# bug#7798
-create table t1(a int primary key, b int not null, index(b));
-insert into t1 values (1,1), (2,2);
-connect (con1,localhost,root,,test);
-connect (con2,localhost,root,,test);
-connection con1;
-set autocommit=0;
-begin;
-select count(*) from t1;
-connection con2;
-ALTER TABLE t1 ADD COLUMN c int;
-connection con1;
-select a from t1 where b = 2;
-show tables;
-drop table t1;
+# create table t1(a int primary key, b int not null, c int, index(b));
+# insert into t1 values (1,1,1), (2,2,2);
+# connect (con1,localhost,root,,test);
+# connect (con2,localhost,root,,test);
+# connection con1;
+# set autocommit=0;
+# begin;
+# select count(*) from t1;
+# connection con2;
+# ALTER TABLE t1 ADD COLUMN c int
+# connection con1;
+# select a from t1 where b = 2;
+# show tables;
+# drop table t1;
+#
# mysqld 5.0.13 crash, no bug#
create table t1 (a int, c varchar(10),
=== modified file 'mysql-test/suite/rpl/r/rpl_locktrans_falcon.result'
--- a/mysql-test/suite/rpl/r/rpl_locktrans_falcon.result 2008-12-15 12:41:31 +0000
+++ b/mysql-test/suite/rpl/r/rpl_locktrans_falcon.result 2009-03-06 22:17:00 +0000
@@ -394,6 +394,17 @@ ERROR 0A000: LOCK is not allowed in stor
CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW
LOCK TABLE t2 IN EXCLUSIVE MODE;
ERROR 0A000: LOCK is not allowed in stored procedures
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
## Cleanup.
SET AUTOCOMMIT= 1;
UNLOCK TABLES;
=== modified file 'mysql-test/suite/rpl/r/rpl_locktrans_innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_locktrans_innodb.result 2009-01-26 16:03:39 +0000
+++ b/mysql-test/suite/rpl/r/rpl_locktrans_innodb.result 2009-03-06 22:17:00 +0000
@@ -926,6 +926,17 @@ TRUNCATE t1;
TRUNCATE t2;
COMMIT;
DROP TRIGGER t1_ai;
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
## Cleanup.
SET AUTOCOMMIT= 1;
UNLOCK TABLES;
=== modified file 'mysql-test/suite/rpl/r/rpl_locktrans_myisam.result'
--- a/mysql-test/suite/rpl/r/rpl_locktrans_myisam.result 2008-12-24 10:48:24 +0000
+++ b/mysql-test/suite/rpl/r/rpl_locktrans_myisam.result 2009-03-06 22:17:00 +0000
@@ -439,6 +439,19 @@ ERROR 0A000: LOCK is not allowed in stor
CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW
LOCK TABLE t2 IN EXCLUSIVE MODE;
ERROR 0A000: LOCK is not allowed in stored procedures
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+UNLOCK TABLES;
## Cleanup.
SET AUTOCOMMIT= 1;
UNLOCK TABLES;
=== modified file 'mysql-test/suite/rpl/t/disabled.def'
--- a/mysql-test/suite/rpl/t/disabled.def 2009-02-14 11:23:14 +0000
+++ b/mysql-test/suite/rpl/t/disabled.def 2009-03-06 22:17:00 +0000
@@ -17,3 +17,5 @@ rpl_binlog_corruption : BUG#41793 2
rpl_extraCol_falcon : Bug#40930 2008-11-21 johnemb rpl.rpl_extraCol_falcon fails
doing STOP SLAVE (on Windows PB2)
rpl_cross_version : Bug#42311 2009-01-23 aelkin
rpl_log_pos : Bug#42858 2009-02-14 alik rpl.rpl_log_pos fails, thus was
disabled
+rpl_failed_optimize : WL#4284: Can't optimize table used by a pending transaction
(there is metadata lock on the table).
+rpl_read_only : WL#4284: Setting Read only won't succeed until all metadata
locks are released.
=== modified file 'mysql-test/suite/sys_vars/t/autocommit_func.test'
--- a/mysql-test/suite/sys_vars/t/autocommit_func.test 2008-12-19 15:12:15 +0000
+++ b/mysql-test/suite/sys_vars/t/autocommit_func.test 2009-03-06 22:17:00 +0000
@@ -153,6 +153,10 @@ SELECT * from t1;
CONNECTION test_con2;
SELECT * from t1;
+--echo ## Commit changes
+CONNECTION test_con1;
+COMMIT;
+
--echo ## Dropping table t1 ##
DROP table t1;
=== modified file 'mysql-test/t/flush_block_commit.test'
--- a/mysql-test/t/flush_block_commit.test 2006-12-26 16:22:17 +0000
+++ b/mysql-test/t/flush_block_commit.test 2009-03-06 22:17:00 +0000
@@ -21,16 +21,13 @@ create table t1 (a int) engine=innodb;
begin;
insert into t1 values(1);
connection con2;
-flush tables with read lock;
-select * from t1;
+--send flush tables with read lock;
connection con1;
-send commit; # blocked by con2
-sleep 1;
+commit;
connection con2;
-select * from t1; # verify con1 was blocked and data did not move
+--reap
+select * from t1;
unlock tables;
-connection con1;
-reap;
# No deadlock ?
@@ -47,6 +44,7 @@ connection con1;
commit; # should not be blocked by con3
connection con2;
reap;
+commit;
connection con3;
reap;
unlock tables;
@@ -60,8 +58,6 @@ connection con1;
begin;
insert into t1 values(10);
flush tables with read lock;
-commit;
-unlock tables;
connection con2;
flush tables with read lock; # bug caused hang here
unlock tables;
@@ -71,6 +67,24 @@ unlock tables;
begin;
select * from t1;
show create database test;
+commit;
+
+# GLR blocks new transactions
+connection con1;
+flush tables with read lock;
+connection con2;
+begin;
+--send insert into t1 values (1);
+connection con1;
+let $wait_condition=
+ select count(*) = 1 from information_schema.processlist
+ where state = "Waiting for release of readlock" and
+ info = "insert into t1 values (1)";
+--source include/wait_condition.inc
+unlock tables;
+connection con2;
+--reap
+commit;
drop table t1;
=== modified file 'mysql-test/t/flush_block_commit_notembedded.test'
--- a/mysql-test/t/flush_block_commit_notembedded.test 2007-06-15 16:56:11 +0000
+++ b/mysql-test/t/flush_block_commit_notembedded.test 2009-03-06 22:17:00 +0000
@@ -17,12 +17,12 @@ connection con1;
create table t1 (a int) engine=innodb;
reset master;
set autocommit=0;
-insert t1 values (1);
+select 1;
connection con2;
flush tables with read lock;
show master status;
connection con1;
-send commit;
+send insert into t1 values (1);
connection con2;
sleep 1;
show master status;
=== modified file 'mysql-test/t/innodb.test'
--- a/mysql-test/t/innodb.test 2009-01-26 16:32:29 +0000
+++ b/mysql-test/t/innodb.test 2009-03-06 22:17:00 +0000
@@ -1797,16 +1797,15 @@ connect (b,localhost,root,,);
connection a;
create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
insert into t1(a) values (1),(2),(3);
+delimiter |;
+create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5,
NEW.c = NEW.a / 10; end |
+delimiter ;|
commit;
connection b;
set autocommit = 0;
update t1 set b = 5 where a = 2;
connection a;
-delimiter |;
-create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5,
NEW.c = NEW.a / 10; end |
-delimiter ;|
set autocommit = 0;
-connection a;
insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100),
(11),(21),(31),(41),(51),(61),(71),(81),(91),(101),
(12),(22),(32),(42),(52),(62),(72),(82),(92),(102),
@@ -1870,6 +1869,9 @@ insert into t2(a) values(8);
delete from t2 where a = 3;
update t4 set b = b + 1 where a = 3;
commit;
+connection a;
+commit;
+connection b;
drop trigger t1t;
drop trigger t2t;
drop trigger t3t;
=== modified file 'mysql-test/t/lock.test'
--- a/mysql-test/t/lock.test 2008-10-21 23:12:53 +0000
+++ b/mysql-test/t/lock.test 2009-03-06 22:17:00 +0000
@@ -281,5 +281,20 @@ drop table t1;
drop view v1;
--echo #
+--echo # WL#4284: Transactional DDL locking
+--echo #
+--echo # FLUSH PRIVILEGES should not implicitly unlock locked tables.
+--echo #
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (c1 int);
+lock tables t1 read;
+--error ER_TABLE_NOT_LOCKED
+flush privileges;
+unlock tables;
+drop table t1;
+
+--echo #
--echo # End of 6.0 tests.
--echo #
=== modified file 'mysql-test/t/partition_innodb_semi_consistent.test'
--- a/mysql-test/t/partition_innodb_semi_consistent.test 2009-01-13 22:12:16 +0000
+++ b/mysql-test/t/partition_innodb_semi_consistent.test 2009-03-06 22:17:00 +0000
@@ -157,7 +157,7 @@ connection con1;
--echo # 3. test for updated key column:
TRUNCATE t1;
-TRUNCATE t2;
+DELETE FROM t2;
INSERT INTO t1 VALUES (1,'init');
=== modified file 'mysql-test/t/read_only_innodb.test'
--- a/mysql-test/t/read_only_innodb.test 2008-04-08 05:20:58 +0000
+++ b/mysql-test/t/read_only_innodb.test 2009-03-06 22:17:00 +0000
@@ -28,15 +28,16 @@ BEGIN;
insert into table_11733 values(11733);
connection default;
-set global read_only=1;
+send set global read_only=1;
connection con1;
select @@global.read_only;
+-- error ER_LOCK_DEADLOCK
select * from table_11733 ;
--- error ER_OPTION_PREVENTS_STATEMENT
COMMIT;
connection default;
+reap;
set global read_only=0;
drop table table_11733 ;
drop user test@localhost;
=== modified file 'mysql-test/t/xa.test'
--- a/mysql-test/t/xa.test 2008-10-23 20:56:03 +0000
+++ b/mysql-test/t/xa.test 2009-03-06 22:17:00 +0000
@@ -72,9 +72,10 @@ xa rollback 'testa','testb';
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
select * from t1;
-drop table t1;
disconnect con1;
+connection default;
+drop table t1;
#
# Bug#28323: Server crashed in xid cache operations
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2009-03-04 13:33:47 +0000
+++ b/sql/log_event.cc 2009-03-06 22:17:00 +0000
@@ -5181,10 +5181,17 @@ void Xid_log_event::print(FILE* file, PR
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Xid_log_event::do_apply_event(Relay_log_info const *rli)
{
+ bool res;
/* For a slave Xid_log_event is COMMIT */
general_log_print(thd, COM_QUERY,
"COMMIT /* implicit, from Xid_log_event */");
- return trans_commit(thd);
+ if (!(res= trans_commit(thd)))
+ {
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
+ }
+ return res;
}
Log_event::enum_skip_reason
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2009-02-23 14:53:18 +0000
+++ b/sql/mysql_priv.h 2009-03-06 22:17:00 +0000
@@ -792,7 +792,7 @@ extern my_decimal decimal_zero;
void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
-void close_thread_tables(THD *thd, bool skip_mdl= 0);
+void close_thread_tables(THD *thd, bool is_back_off= 0);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);
=== modified file 'sql/rpl_injector.cc'
--- a/sql/rpl_injector.cc 2008-12-13 11:02:16 +0000
+++ b/sql/rpl_injector.cc 2009-03-06 22:17:00 +0000
@@ -83,17 +83,25 @@ int injector::transaction::commit()
explicitly.
*/
trans_commit_stmt(m_thd);
- trans_commit(m_thd);
+ if (!trans_commit(m_thd))
+ {
+ close_thread_tables(m_thd);
+ if (!m_thd->locked_tables_mode)
+ m_thd->mdl_context.release_all_locks();
+ }
DBUG_RETURN(0);
}
int injector::transaction::rollback()
{
DBUG_ENTER("injector::transaction::rollback()");
- //psergey ha_autocommit_or_rollback(m_thd, 1 /* error to get rollback */);
trans_rollback_stmt(m_thd);
- //psergey end_trans(m_thd, ROLLBACK);
- trans_rollback(m_thd);
+ if (!trans_rollback(m_thd))
+ {
+ close_thread_tables(m_thd);
+ if (!m_thd->locked_tables_mode)
+ m_thd->mdl_context.release_all_locks();
+ }
DBUG_RETURN(0);
}
=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc 2009-03-04 13:31:31 +0000
+++ b/sql/rpl_rli.cc 2009-03-06 22:17:00 +0000
@@ -1170,6 +1170,8 @@ void Relay_log_info::cleanup_context(THD
}
m_table_map.clear_tables();
slave_close_thread_tables(thd);
+ if (error && !thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
clear_flag(IN_STMT);
/*
Cleanup for the flags that have been set at do_apply_event.
@@ -1182,13 +1184,6 @@ void Relay_log_info::cleanup_context(THD
void Relay_log_info::clear_tables_to_lock()
{
- /*
- Deallocating elements of table list below will also free memory where
- meta-data locks are stored. So we want to be sure that we don't have
- any references to this memory left.
- */
- DBUG_ASSERT(!current_thd->mdl_context.has_locks());
-
while (tables_to_lock)
{
uchar* to_free= reinterpret_cast<uchar*>(tables_to_lock);
@@ -1207,12 +1202,6 @@ void Relay_log_info::clear_tables_to_loc
void Relay_log_info::slave_close_thread_tables(THD *thd)
{
- /*
- Since we use same memory chunks for allocation of metadata lock
- objects for tables as we use for allocating corresponding elements
- of 'tables_to_lock' list, we have to release metadata locks by
- closing tables before calling clear_tables_to_lock().
- */
close_thread_tables(thd);
clear_tables_to_lock();
}
=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc 2009-03-04 10:04:58 +0000
+++ b/sql/set_var.cc 2009-03-06 22:17:00 +0000
@@ -3497,9 +3497,15 @@ static bool set_option_autocommit(THD *t
need to commit any outstanding transactions.
*/
if (var->save_result.ulong_value != 0 &&
- (thd->options & OPTION_NOT_AUTOCOMMIT) &&
- trans_commit(thd))
- return 1;
+ (thd->options & OPTION_NOT_AUTOCOMMIT))
+ {
+ if (trans_commit(thd))
+ return TRUE;
+
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
+ }
if (var->save_result.ulong_value != 0)
thd->options&= ~((sys_var_thd_bit*) var->var)->bit_flag;
=== modified file 'sql/slave.cc'
--- a/sql/slave.cc 2009-02-23 14:53:18 +0000
+++ b/sql/slave.cc 2009-03-06 22:17:00 +0000
@@ -2162,6 +2162,9 @@ static int exec_relay_log_event(THD* thd
{
exec_res= 0;
trans_rollback(thd);
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
/* chance for concurrent connection to get more locks */
safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
(CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc 2009-03-04 10:04:58 +0000
+++ b/sql/sql_acl.cc 2009-03-06 22:17:00 +0000
@@ -30,6 +30,7 @@
#include <stdarg.h>
#include "sp_head.h"
#include "sp.h"
+#include "transaction.h"
time_t mysql_db_table_last_check= 0L;
@@ -676,9 +677,6 @@ my_bool acl_reload(THD *thd)
my_bool return_val= 1;
DBUG_ENTER("acl_reload");
- /* Can't have locked tables here. */
- thd->locked_tables_list.unlock_locked_tables(thd);
-
/*
To avoid deadlocks we should obtain table locks before
obtaining acl_cache->lock mutex.
@@ -732,7 +730,10 @@ my_bool acl_reload(THD *thd)
if (old_initialized)
pthread_mutex_unlock(&acl_cache->lock);
end:
+ trans_commit_implicit(thd);
close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
DBUG_RETURN(return_val);
}
@@ -3823,7 +3824,10 @@ my_bool grant_reload(THD *thd)
free_root(&old_mem,MYF(0));
}
rw_unlock(&LOCK_grant);
+ trans_commit_implicit(thd);
close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
/*
It is OK failing to load procs_priv table because we may be
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2009-03-04 13:33:47 +0000
+++ b/sql/sql_base.cc 2009-03-06 22:17:00 +0000
@@ -1475,11 +1475,22 @@ void close_thread_tables(THD *thd,
if (thd->open_tables)
close_open_tables(thd);
- thd->mdl_context.release_all_locks();
if (!is_back_off)
{
thd->mdl_context.remove_all_requests();
}
+
+ /*
+ Defer the release of metadata locks until the current transaction
+ is either committed or rolled back. This prevents other statements
+ from modifying the table for the entire duration of this transaction.
+ This provides commitment ordering for guaranteeing serializability
+ across multiple transactions.
+ */
+ if (!thd->in_multi_stmt_transaction() ||
+ (thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
+ thd->mdl_context.release_all_locks();
+
DBUG_VOID_RETURN;
}
@@ -3618,6 +3629,7 @@ int open_tables(THD *thd, TABLE_LIST **s
/* Also used for indicating that prelocking is need */
TABLE_LIST **query_tables_last_own;
bool safe_to_ignore_table;
+ bool has_locks= thd->mdl_context.has_locks();
DBUG_ENTER("open_tables");
/*
@@ -3759,6 +3771,18 @@ int open_tables(THD *thd, TABLE_LIST **s
if (action)
{
/*
+ We have met a exclusive metadata lock or a old version of table and
+ we are inside a transaction that already hold locks. We can't follow
+ the locking protocol in this scenario as it might lead to deadlocks.
+ */
+ if (thd->in_multi_stmt_transaction() && has_locks)
+ {
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ result= -1;
+ goto err;
+ }
+
+ /*
We have met exclusive metadata lock or old version of table. Now we
have to close all tables which are not up to date/release metadata
locks. We also have to throw away set of prelocked tables (and thus
@@ -4625,6 +4649,8 @@ void close_tables_for_reopen(THD *thd, T
for (TABLE_LIST *tmp= *tables; tmp; tmp= tmp->next_global)
tmp->table= 0;
close_thread_tables(thd, is_back_off);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
}
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2009-03-04 13:33:47 +0000
+++ b/sql/sql_class.cc 2009-03-06 22:17:00 +0000
@@ -946,6 +946,17 @@ void THD::cleanup(void)
trans_rollback(this);
xid_cache_delete(&transaction.xid_state);
}
+
+ /*
+ Thread could be in the middle of a ongoing transaction
+ that just got rolled back. Release any metadata locks.
+ */
+ if (!locked_tables_mode)
+ {
+ DBUG_ASSERT(open_tables == NULL);
+ mdl_context.release_all_locks();
+ }
+
locked_tables_list.unlock_locked_tables(this);
#if defined(ENABLED_DEBUG_SYNC)
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2009-03-04 13:33:47 +0000
+++ b/sql/sql_parse.cc 2009-03-06 22:17:00 +0000
@@ -133,11 +133,11 @@ static bool some_non_temp_table_to_be_up
@param mask Bitmask used for the SQL command match.
*/
-static bool opt_implicit_commit(THD *thd, uint mask)
+static bool stmt_causes_implicit_commit(THD *thd, uint mask)
{
LEX *lex= thd->lex;
- bool res= FALSE, skip= FALSE;
- DBUG_ENTER("opt_implicit_commit");
+ bool skip= FALSE;
+ DBUG_ENTER("stmt_causes_implicit_commit");
if (!(sql_command_flags[lex->sql_command] & mask))
DBUG_RETURN(FALSE);
@@ -158,15 +158,7 @@ static bool opt_implicit_commit(THD *thd
break;
}
- if (!skip)
- {
- /* Commit or rollback the statement transaction. */
- thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
- /* Commit the normal transaction if one is active. */
- res= trans_commit_implicit(thd);
- }
-
- DBUG_RETURN(res);
+ DBUG_RETURN(!skip);
}
@@ -1225,6 +1217,9 @@ bool dispatch_command(enum enum_server_c
ulong options= (ulong) (uchar) packet[0];
if (trans_commit_implicit(thd))
break;
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
if (check_global_access(thd,RELOAD_ACL))
break;
general_log_print(thd, command, NullS);
@@ -1232,6 +1227,9 @@ bool dispatch_command(enum enum_server_c
break;
if (trans_commit_implicit(thd))
break;
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
my_ok(thd);
break;
}
@@ -1997,8 +1995,18 @@ mysql_execute_command(THD *thd)
not run in it's own transaction it may simply never appear on
the slave in case the outside transaction rolls back.
*/
- if (opt_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
- goto error;
+ if (stmt_causes_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
+ {
+ /* Commit or rollback the statement transaction. */
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ /* Commit the normal transaction if one is active. */
+ if (trans_commit_implicit(thd))
+ goto error;
+ /* Close tables and release metadata locks. */
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
+ }
switch (lex->sql_command) {
@@ -3460,6 +3468,7 @@ ddl_blocker_err:
if (thd->options & OPTION_TABLE_LOCK)
{
trans_commit_implicit(thd);
+ thd->mdl_context.release_all_locks();
thd->options&= ~(OPTION_TABLE_LOCK);
}
if (thd->global_read_lock)
@@ -3515,6 +3524,8 @@ ddl_blocker_err:
/* we must end the trasaction first, regardless of anything */
if (trans_commit_implicit(thd))
goto error;
+ /* release transactional metadata locks. */
+ thd->mdl_context.release_all_locks();
alloc_mdl_requests(all_tables, thd->locked_tables_list.locked_tables_root());
@@ -3538,6 +3549,13 @@ ddl_blocker_err:
*/
trans_rollback_stmt(thd);
trans_commit_implicit(thd);
+ /*
+ Close tables and release metadata locks otherwise a later call to
+ close_thread_tables might not release the locks if autocommit is off.
+ */
+ close_thread_tables(thd);
+ DBUG_ASSERT(!thd->locked_tables_mode);
+ thd->mdl_context.release_all_locks();
thd->options&= ~(OPTION_TABLE_LOCK);
}
else
@@ -4040,6 +4058,8 @@ ddl_blocker_err:
thd->locked_tables_mode == LTM_LOCK_TABLES);
if (trans_commit(thd))
goto error;
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
/* Begin transaction with the same isolation level. */
if (lex->tx_chain && trans_begin(thd))
goto error;
@@ -4054,6 +4074,8 @@ ddl_blocker_err:
thd->locked_tables_mode == LTM_LOCK_TABLES);
if (trans_rollback(thd))
goto error;
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
/* Begin transaction with the same isolation level. */
if (lex->tx_chain && trans_begin(thd))
goto error;
@@ -4413,6 +4435,12 @@ create_sp_error:
if (trans_commit_implicit(thd))
goto error;
+
+ close_thread_tables(thd);
+
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sp_automatic_privileges && !opt_noacl &&
sp_revoke_privileges(thd, db, name,
@@ -4559,11 +4587,15 @@ create_sp_error:
case SQLCOM_XA_COMMIT:
if (trans_xa_commit(thd))
goto error;
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
my_ok(thd);
break;
case SQLCOM_XA_ROLLBACK:
if (trans_xa_rollback(thd))
goto error;
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
my_ok(thd);
break;
case SQLCOM_XA_RECOVER:
@@ -4703,10 +4735,20 @@ finish:
start_waiting_global_read_lock(thd);
}
- /* If commit fails, we should be able to reset the OK status. */
- thd->stmt_da->can_overwrite_status= TRUE;
- opt_implicit_commit(thd, CF_IMPLICIT_COMMIT_END);
- thd->stmt_da->can_overwrite_status= FALSE;
+ if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
+ {
+ /* If commit fails, we should be able to reset the OK status. */
+ thd->stmt_da->can_overwrite_status= TRUE;
+ /* Commit or rollback the statement transaction. */
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ /* Commit the normal transaction if one is active. */
+ trans_commit_implicit(thd);
+ /* Close tables and release metadata locks. */
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
+ thd->stmt_da->can_overwrite_status= FALSE;
+ }
DBUG_RETURN(res || thd->is_error());
@@ -6680,6 +6722,9 @@ bool reload_acl_and_cache(THD *thd, ulon
query_cache.flush(); // RESET QUERY CACHE
}
#endif /*HAVE_QUERY_CACHE*/
+
+ DBUG_ASSERT(thd->locked_tables_mode || !thd->mdl_context.has_locks());
+
/*
Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
(see sql_yacc.yy)
=== modified file 'sql/sql_servers.cc'
--- a/sql/sql_servers.cc 2009-03-02 21:18:26 +0000
+++ b/sql/sql_servers.cc 2009-03-06 22:17:00 +0000
@@ -39,6 +39,7 @@
#include <stdarg.h>
#include "sp_head.h"
#include "sp.h"
+#include "transaction.h"
/*
We only use 1 mutex to guard the data structures - THR_LOCK_servers.
@@ -223,9 +224,6 @@ bool servers_reload(THD *thd)
bool return_val= TRUE;
DBUG_ENTER("servers_reload");
- /* Can't have locked tables here */
- thd->locked_tables_list.unlock_locked_tables(thd);
-
DBUG_PRINT("info", ("locking servers_cache"));
rw_wrlock(&THR_LOCK_servers);
@@ -251,7 +249,10 @@ bool servers_reload(THD *thd)
}
end:
+ trans_commit_implicit(thd);
close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
DBUG_PRINT("info", ("unlocking servers_cache"));
rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(return_val);
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2009-03-04 13:33:47 +0000
+++ b/sql/sql_table.cc 2009-03-06 22:17:00 +0000
@@ -4393,6 +4393,8 @@ static bool mysql_admin_table(THD* thd,
trans_commit_stmt(thd);
trans_commit(thd);
close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
lex->reset_query_tables_list(FALSE);
table->table=0; // For query cache
if (protocol->write())
@@ -4442,7 +4444,10 @@ static bool mysql_admin_table(THD* thd,
{
DBUG_PRINT("admin", ("recreating table"));
trans_rollback_stmt(thd);
+ trans_rollback(thd);
close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
tmp_disable_binlog(thd); // binlogging is done by caller if wanted
result_code= mysql_recreate_table(thd, table);
reenable_binlog(thd);
@@ -4556,13 +4561,16 @@ send_result_message:
We have to end the row, so analyze could return more rows.
*/
trans_commit_stmt(thd);
+ trans_commit(thd);
+ close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
protocol->store(STRING_WITH_LEN("note"), system_charset_info);
protocol->store(STRING_WITH_LEN(
"Table does not support optimize, doing recreate + analyze instead"),
system_charset_info);
if (protocol->write())
goto err;
- close_thread_tables(thd);
DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze..."));
TABLE_LIST *save_next_local= table->next_local,
*save_next_global= table->next_global;
@@ -4579,7 +4587,10 @@ send_result_message:
if (thd->stmt_da->is_ok())
thd->stmt_da->reset_diagnostics_area();
trans_commit_stmt(thd);
+ trans_commit(thd);
close_thread_tables(thd);
+ if (!thd->locked_tables_mode)
+ thd->mdl_context.release_all_locks();
if (!result_code) // recreation went ok
{
if ((table->table= open_ltable(thd, table, lock_type, 0)) &&
@@ -4673,6 +4684,7 @@ send_result_message:
query_cache_invalidate3(thd, table->table, 0);
}
}
+ /* Error path, a admin command failed. */
trans_commit_stmt(thd);
trans_commit_implicit(thd);
close_thread_tables(thd);
=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc 2009-01-26 17:19:14 +0000
+++ b/sql/transaction.cc 2009-03-06 22:17:00 +0000
@@ -98,6 +98,10 @@ bool trans_begin(THD *thd, uint flags)
thd->locked_tables_list.unlock_locked_tables(thd);
+ DBUG_ASSERT(!thd->locked_tables_mode);
+
+ thd->mdl_context.release_all_locks();
+
if (trans_commit_implicit(thd))
DBUG_RETURN(TRUE);
@@ -336,6 +340,13 @@ bool trans_savepoint(THD *thd, LEX_STRIN
newsv->prev= thd->transaction.savepoints;
thd->transaction.savepoints= newsv;
+ /*
+ Remember the last acquired lock before the savepoint was set.
+ This is used as a marker to only release locks acquired after
+ the setting of this savepoint.
+ */
+ newsv->mdl_savepoint = thd->mdl_context.mdl_savepoint();
+
DBUG_RETURN(FALSE);
}
@@ -380,6 +391,10 @@ bool trans_rollback_to_savepoint(THD *th
thd->transaction.savepoints= sv;
+ /* Release metadata locks that were acquired during this savepoint unit. */
+ if (!res && !thd->locked_tables_mode)
+ thd->mdl_context.rollback_to_savepoint(sv->mdl_savepoint);
+
DBUG_RETURN(test(res));
}
Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20090306221700-365jl9e8liarvz36.bundle