Skip to content

Commit 67551a4

Browse files
Dmitry LenevDmitry Lenev
authored andcommitted
Merge of fix for bug#14188793 - "DEADLOCK CAUSED BY ALTER TABLE DOEN'T CLEAR
STATUS OF ROLLBACKED TRANSACTION" and bug #17054007 - "TRANSACTION IS NOT FULLY ROLLED BACK IN CASE OF INNODB DEADLOCK" into mysql-5.6.
2 parents de3d604 + b07ec61 commit 67551a4

24 files changed

+288
-143
lines changed

mysql-test/include/handler.inc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,8 +1090,7 @@ connection con1;
10901090
connection default;
10911091
--echo #
10921092
--echo # Demonstrate that HANDLER locks and transaction locks
1093-
--echo # reside in the same context, and we don't back-off
1094-
--echo # when have transaction or handler locks.
1093+
--echo # reside in the same context.
10951094
--echo #
10961095
create table t1 (a int, key a (a));
10971096
insert into t1 (a) values (1), (2), (3), (4), (5);
@@ -1112,9 +1111,9 @@ let $wait_condition=select count(*)=1 from information_schema.processlist
11121111
--source include/wait_condition.inc
11131112
--echo # --> connection default
11141113
connection default;
1114+
--echo # We back-off on hitting deadlock condition.
11151115
--error ER_LOCK_DEADLOCK
11161116
handler t0 open;
1117-
--error ER_LOCK_DEADLOCK
11181117
select * from t0;
11191118
handler t1 open;
11201119
commit;

mysql-test/r/handler_innodb.result

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,8 +1107,7 @@ handler t1 close;
11071107
# --> connection default
11081108
#
11091109
# Demonstrate that HANDLER locks and transaction locks
1110-
# reside in the same context, and we don't back-off
1111-
# when have transaction or handler locks.
1110+
# reside in the same context.
11121111
#
11131112
create table t1 (a int, key a (a));
11141113
insert into t1 (a) values (1), (2), (3), (4), (5);
@@ -1128,10 +1127,16 @@ rename table t0 to t3, t1 to t0, t3 to t1;
11281127
# --> connection con1
11291128
# Waiting for 'rename table ...' to get blocked...
11301129
# --> connection default
1130+
# We back-off on hitting deadlock condition.
11311131
handler t0 open;
11321132
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
11331133
select * from t0;
1134-
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
1134+
a
1135+
1
1136+
2
1137+
3
1138+
4
1139+
5
11351140
handler t1 open;
11361141
commit;
11371142
handler t1 close;

mysql-test/r/handler_myisam.result

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,8 +1103,7 @@ handler t1 close;
11031103
# --> connection default
11041104
#
11051105
# Demonstrate that HANDLER locks and transaction locks
1106-
# reside in the same context, and we don't back-off
1107-
# when have transaction or handler locks.
1106+
# reside in the same context.
11081107
#
11091108
create table t1 (a int, key a (a));
11101109
insert into t1 (a) values (1), (2), (3), (4), (5);
@@ -1124,10 +1123,16 @@ rename table t0 to t3, t1 to t0, t3 to t1;
11241123
# --> connection con1
11251124
# Waiting for 'rename table ...' to get blocked...
11261125
# --> connection default
1126+
# We back-off on hitting deadlock condition.
11271127
handler t0 open;
11281128
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
11291129
select * from t0;
1130-
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
1130+
a
1131+
1
1132+
2
1133+
3
1134+
4
1135+
5
11311136
handler t1 open;
11321137
commit;
11331138
handler t1 close;

mysql-test/r/mdl_sync.result

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,15 +1977,11 @@ rename table t2 to t0, t1 to t2, t0 to t1;;
19771977
# for 'deadlock_con1' which holds shared metadata lock on 't2'.
19781978
#
19791979
# The below statement should not wait as doing so will cause deadlock.
1980-
# Instead it should fail and emit ER_LOCK_DEADLOCK statement.
1980+
# Instead it should fail and emit ER_LOCK_DEADLOCK statement and
1981+
# transaction should be rolled back.
19811982
select * from t1;
19821983
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
19831984
#
1984-
# Let us check that failure of the above statement has not released
1985-
# metadata lock on table 't1', i.e. that RENAME TABLE is still blocked.
1986-
# Commit transaction to unblock RENAME TABLE.
1987-
commit;
1988-
#
19891985
# Switching to connection 'default'.
19901986
# Reap RENAME TABLE.
19911987
#
@@ -2022,16 +2018,10 @@ unlock tables;
20222018
# Switching to connection 'deadlock_con1'.
20232019
# Since the latest RENAME TABLE entered in deadlock with SELECT
20242020
# statement the latter should be aborted and emit ER_LOCK_DEADLOCK
2025-
# error.
2021+
# error and transaction should be rolled back.
20262022
# Reap SELECT * FROM t1.
20272023
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
20282024
#
2029-
# Again let us check that failure of the SELECT statement has not
2030-
# released metadata lock on table 't2', i.e. that the latest RENAME
2031-
# is blocked.
2032-
# Commit transaction to unblock this RENAME TABLE.
2033-
commit;
2034-
#
20352025
# Switching to connection 'deadlock_con2'.
20362026
# Reap RENAME TABLE ... .
20372027
#
@@ -2065,14 +2055,10 @@ alter table t1 add column j int, rename to t2;;
20652055
# metadata lock on 't2' and starts waiting for connection
20662056
# 'deadlock_con1' which holds shared lock on 't1'.
20672057
# The below statement should not wait as it will cause deadlock.
2068-
# An appropriate error should be reported instead.
2058+
# An appropriate error should be reported instead and transaction
2059+
# should be rolled back.
20692060
select * from t2;
20702061
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
2071-
# Again let us check that failure of the above statement has not
2072-
# released all metadata locks in connection 'deadlock_con1' and
2073-
# so ALTER TABLE ... RENAME is still blocked.
2074-
# Commit transaction to unblock ALTER TABLE ... RENAME.
2075-
commit;
20762062
#
20772063
# Switching to connection 'default'.
20782064
# Reap ALTER TABLE ... RENAME.
@@ -2581,12 +2567,6 @@ set debug_sync='mdl_acquire_lock_wait SIGNAL alter_go';
25812567
update t1 set c3=c3+1 where c2 = 3;
25822568
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
25832569
#
2584-
# Let us check that failure of the above statement has not released
2585-
# metadata lock on table 't1', i.e. that ALTER TABLE is still blocked.
2586-
# Unblock ALTER TABLE by commiting transaction and thus releasing
2587-
# metadata lock on 't1'.
2588-
commit;
2589-
#
25902570
# Switching to connection 'con46273'.
25912571
# Reap ALTER TABLE.
25922572
#

mysql-test/t/mdl_sync.test

Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2785,21 +2785,11 @@ let $wait_condition=
27852785
--source include/wait_condition.inc
27862786
--echo #
27872787
--echo # The below statement should not wait as doing so will cause deadlock.
2788-
--echo # Instead it should fail and emit ER_LOCK_DEADLOCK statement.
2788+
--echo # Instead it should fail and emit ER_LOCK_DEADLOCK statement and
2789+
--echo # transaction should be rolled back.
27892790
--error ER_LOCK_DEADLOCK
27902791
select * from t1;
27912792

2792-
--echo #
2793-
--echo # Let us check that failure of the above statement has not released
2794-
--echo # metadata lock on table 't1', i.e. that RENAME TABLE is still blocked.
2795-
let $wait_condition=
2796-
select count(*) = 1 from information_schema.processlist
2797-
where state = "Waiting for table metadata lock" and
2798-
info = "rename table t2 to t0, t1 to t2, t0 to t1";
2799-
--source include/wait_condition.inc
2800-
--echo # Commit transaction to unblock RENAME TABLE.
2801-
commit;
2802-
28032793
--echo #
28042794
--echo # Switching to connection 'default'.
28052795
connection default;
@@ -2862,23 +2852,11 @@ unlock tables;
28622852
connection deadlock_con1;
28632853
--echo # Since the latest RENAME TABLE entered in deadlock with SELECT
28642854
--echo # statement the latter should be aborted and emit ER_LOCK_DEADLOCK
2865-
--echo # error.
2855+
--echo # error and transaction should be rolled back.
28662856
--echo # Reap SELECT * FROM t1.
28672857
--error ER_LOCK_DEADLOCK
28682858
--reap
28692859

2870-
--echo #
2871-
--echo # Again let us check that failure of the SELECT statement has not
2872-
--echo # released metadata lock on table 't2', i.e. that the latest RENAME
2873-
--echo # is blocked.
2874-
let $wait_condition=
2875-
select count(*) = 1 from information_schema.processlist
2876-
where state = "Waiting for table metadata lock" and
2877-
info = "rename table t1 to t0, t2 to t1, t0 to t2";
2878-
--source include/wait_condition.inc
2879-
--echo # Commit transaction to unblock this RENAME TABLE.
2880-
commit;
2881-
28822860
--echo #
28832861
--echo # Switching to connection 'deadlock_con2'.
28842862
connection deadlock_con2;
@@ -2927,22 +2905,11 @@ let $wait_condition=
29272905
--source include/wait_condition.inc
29282906

29292907
--echo # The below statement should not wait as it will cause deadlock.
2930-
--echo # An appropriate error should be reported instead.
2908+
--echo # An appropriate error should be reported instead and transaction
2909+
--echo # should be rolled back.
29312910
--error ER_LOCK_DEADLOCK
29322911
select * from t2;
29332912

2934-
--echo # Again let us check that failure of the above statement has not
2935-
--echo # released all metadata locks in connection 'deadlock_con1' and
2936-
--echo # so ALTER TABLE ... RENAME is still blocked.
2937-
let $wait_condition=
2938-
select count(*) = 1 from information_schema.processlist
2939-
where state = "Waiting for table metadata lock" and
2940-
info = "alter table t1 add column j int, rename to t2";
2941-
--source include/wait_condition.inc
2942-
2943-
--echo # Commit transaction to unblock ALTER TABLE ... RENAME.
2944-
commit;
2945-
29462913
--echo #
29472914
--echo # Switching to connection 'default'.
29482915
connection default;
@@ -3814,19 +3781,6 @@ set debug_sync='mdl_acquire_lock_wait SIGNAL alter_go';
38143781
--error ER_LOCK_DEADLOCK
38153782
update t1 set c3=c3+1 where c2 = 3;
38163783

3817-
--echo #
3818-
--echo # Let us check that failure of the above statement has not released
3819-
--echo # metadata lock on table 't1', i.e. that ALTER TABLE is still blocked.
3820-
let $wait_condition=
3821-
select count(*) = 1 from information_schema.processlist
3822-
where state = "Waiting for table metadata lock" and
3823-
info = "alter table t1 add column e int, rename to t2";
3824-
--source include/wait_condition.inc
3825-
3826-
--echo # Unblock ALTER TABLE by commiting transaction and thus releasing
3827-
--echo # metadata lock on 't1'.
3828-
commit;
3829-
38303784
--echo #
38313785
--echo # Switching to connection 'con46273'.
38323786
connection con46273;

plugin/innodb_memcached/innodb_memcache/src/handler_api.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ handler_binlog_rollback(
226226
{
227227
THD* thd = static_cast<THD*>(my_thd);
228228

229+
/*
230+
Memcached plugin doesn't use thd_mark_transaction_to_rollback()
231+
on deadlocks. So no special handling for this flag is needed.
232+
*/
229233
if (tc_log) {
230234
tc_log->rollback(thd, true);
231235
}

sql/ha_ndbcluster_binlog.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -3371,6 +3371,12 @@ ndb_binlog_index_table__write_rows(THD *thd,
33713371
// Close the tables this thread has opened
33723372
close_thread_tables(thd);
33733373

3374+
/*
3375+
There should be no need for rolling back transaction due to deadlock
3376+
(since ndb_binlog_index is non transactional).
3377+
*/
3378+
DBUG_ASSERT(! thd->transaction_rollback_request);
3379+
33743380
// Release MDL locks on the opened table
33753381
thd->mdl_context.release_transactional_locks();
33763382

sql/handler.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,11 +1550,16 @@ int ha_rollback_low(THD *thd, bool all)
15501550
trans->ha_list= 0;
15511551
trans->no_2pc=0;
15521552
trans->rw_ha_count= 0;
1553-
if (all && thd->transaction_rollback_request &&
1554-
thd->transaction.xid_state.xa_state != XA_NOTR)
1555-
thd->transaction.xid_state.rm_error= thd->get_stmt_da()->sql_errno();
15561553
}
15571554

1555+
/*
1556+
Thanks to possibility of MDL deadlock rollback request can come even if
1557+
transaction hasn't been started in any transactional storage engine.
1558+
*/
1559+
if (all && thd->transaction_rollback_request &&
1560+
thd->transaction.xid_state.xa_state != XA_NOTR)
1561+
thd->transaction.xid_state.rm_error= thd->get_stmt_da()->sql_errno();
1562+
15581563
(void) RUN_HOOK(transaction, after_rollback, (thd, all));
15591564
return error;
15601565
}

sql/log_event.cc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6537,6 +6537,8 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
65376537
thd->get_stmt_da()->set_overwrite_status(false);
65386538
close_thread_tables(thd);
65396539
/*
6540+
- If transaction rollback was requested due to deadlock
6541+
perform it and release metadata locks.
65406542
- If inside a multi-statement transaction,
65416543
defer the release of metadata locks until the current
65426544
transaction is either committed or rolled back. This prevents
@@ -6546,7 +6548,12 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
65466548
- If in autocommit mode, or outside a transactional context,
65476549
automatically release metadata locks of the current statement.
65486550
*/
6549-
if (! thd->in_multi_stmt_transaction_mode())
6551+
if (thd->transaction_rollback_request)
6552+
{
6553+
trans_rollback_implicit(thd);
6554+
thd->mdl_context.release_transactional_locks();
6555+
}
6556+
else if (! thd->in_multi_stmt_transaction_mode())
65506557
thd->mdl_context.release_transactional_locks();
65516558
else
65526559
thd->mdl_context.release_statement_locks();
@@ -11287,7 +11294,10 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
1128711294
Xid_log_event will come next which will, if some transactional engines
1128811295
are involved, commit the transaction and flush the pending event to the
1128911296
binlog.
11297+
If there was a deadlock the transaction should have been rolled back
11298+
already. So there should be no need to rollback the transaction.
1129011299
*/
11300+
DBUG_ASSERT(! thd->transaction_rollback_request);
1129111301
error|= (error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd));
1129211302

1129311303
/*

sql/log_event_old.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
18011801
Xid_log_event will come next which will, if some transactional engines
18021802
are involved, commit the transaction and flush the pending event to the
18031803
binlog.
1804+
If there was a deadlock the transaction should have been rolled back
1805+
already. So there should be no need to rollback the transaction.
18041806
*/
1807+
DBUG_ASSERT(! thd->transaction_rollback_request);
18051808
if ((error= (binlog_error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd))))
18061809
rli->report(ERROR_LEVEL, error,
18071810
"Error in %s event: commit of row events failed, "

0 commit comments

Comments
 (0)