mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
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". The problem in the first bug report was that although deadlock involving metadata locks was reported using the same error code and message as InnoDB deadlock it didn't rollback transaction like the latter. This caused confusion to users as in some cases after ER_LOCK_DEADLOCK transaction could have been restarted immediately and in some cases rollback was required. The problem in the second bug report was that although InnoDB deadlock caused transaction rollback in all storage engines it didn't cause release of metadata locks. So concurrent DDL on the tables used in transaction was blocked until implicit or explicit COMMIT or ROLLBACK was issued in the connection which got InnoDB deadlock. The former issue has stemmed from the fact that when support for detection and reporting metadata locks deadlocks was added we erroneously assumed that InnoDB doesn't rollback transaction on deadlock but only last statement (while this is what happens on InnoDB lock timeout actually) and so didn't implement rollback of transactions on MDL deadlocks. The latter issue was caused by the fact that rollback of transaction due to deadlock is carried out by setting THD::transaction_rollback_request flag at the point where deadlock is detected and performing rollback inside of trans_rollback_stmt() call when this flag is set. And trans_rollback_stmt() is not aware of MDL locks, so no MDL locks are released. This patch solves these two problems in the following way: - In case when MDL deadlock is detect transaction rollback is requested by setting THD::transaction_rollback_request flag. - Code performing rollback of transaction if THD::transaction_rollback_request is moved out from trans_rollback_stmt(). Now we handle rollback request on the same level as we call trans_rollback_stmt() and release statement/ transaction MDL locks.
This commit is contained in:
@@ -1104,8 +1104,7 @@ handler t1 close;
|
||||
# --> connection default
|
||||
#
|
||||
# Demonstrate that HANDLER locks and transaction locks
|
||||
# reside in the same context, and we don't back-off
|
||||
# when have transaction or handler locks.
|
||||
# reside in the same context.
|
||||
#
|
||||
create table t1 (a int, key a (a));
|
||||
insert into t1 (a) values (1), (2), (3), (4), (5);
|
||||
@@ -1125,10 +1124,16 @@ rename table t0 to t3, t1 to t0, t3 to t1;
|
||||
# --> connection con1
|
||||
# Waiting for 'rename table ...' to get blocked...
|
||||
# --> connection default
|
||||
# We back-off on hitting deadlock condition.
|
||||
handler t0 open;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
select * from t0;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
handler t1 open;
|
||||
commit;
|
||||
handler t1 close;
|
||||
|
||||
@@ -1100,8 +1100,7 @@ handler t1 close;
|
||||
# --> connection default
|
||||
#
|
||||
# Demonstrate that HANDLER locks and transaction locks
|
||||
# reside in the same context, and we don't back-off
|
||||
# when have transaction or handler locks.
|
||||
# reside in the same context.
|
||||
#
|
||||
create table t1 (a int, key a (a));
|
||||
insert into t1 (a) values (1), (2), (3), (4), (5);
|
||||
@@ -1121,10 +1120,16 @@ rename table t0 to t3, t1 to t0, t3 to t1;
|
||||
# --> connection con1
|
||||
# Waiting for 'rename table ...' to get blocked...
|
||||
# --> connection default
|
||||
# We back-off on hitting deadlock condition.
|
||||
handler t0 open;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
select * from t0;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
handler t1 open;
|
||||
commit;
|
||||
handler t1 close;
|
||||
|
||||
@@ -1843,15 +1843,11 @@ rename table t2 to t0, t1 to t2, t0 to t1;;
|
||||
# for 'deadlock_con1' which holds shared metadata lock on 't2'.
|
||||
#
|
||||
# The below statement should not wait as doing so will cause deadlock.
|
||||
# Instead it should fail and emit ER_LOCK_DEADLOCK statement.
|
||||
# Instead it should fail and emit ER_LOCK_DEADLOCK statement and
|
||||
# transaction should be rolled back.
|
||||
select * from t1;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
#
|
||||
# Let us check that failure of the above statement has not released
|
||||
# metadata lock on table 't1', i.e. that RENAME TABLE is still blocked.
|
||||
# Commit transaction to unblock RENAME TABLE.
|
||||
commit;
|
||||
#
|
||||
# Switching to connection 'default'.
|
||||
# Reap RENAME TABLE.
|
||||
#
|
||||
@@ -1888,16 +1884,10 @@ unlock tables;
|
||||
# Switching to connection 'deadlock_con1'.
|
||||
# Since the latest RENAME TABLE entered in deadlock with SELECT
|
||||
# statement the latter should be aborted and emit ER_LOCK_DEADLOCK
|
||||
# error.
|
||||
# error and transaction should be rolled back.
|
||||
# Reap SELECT * FROM t1.
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
#
|
||||
# Again let us check that failure of the SELECT statement has not
|
||||
# released metadata lock on table 't2', i.e. that the latest RENAME
|
||||
# is blocked.
|
||||
# Commit transaction to unblock this RENAME TABLE.
|
||||
commit;
|
||||
#
|
||||
# Switching to connection 'deadlock_con2'.
|
||||
# Reap RENAME TABLE ... .
|
||||
#
|
||||
@@ -1931,14 +1921,10 @@ alter table t1 add column j int, rename to t2;;
|
||||
# metadata lock on 't2' and starts waiting for connection
|
||||
# 'deadlock_con1' which holds shared lock on 't1'.
|
||||
# The below statement should not wait as it will cause deadlock.
|
||||
# An appropriate error should be reported instead.
|
||||
# An appropriate error should be reported instead and transaction
|
||||
# should be rolled back.
|
||||
select * from t2;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
# Again let us check that failure of the above statement has not
|
||||
# released all metadata locks in connection 'deadlock_con1' and
|
||||
# so ALTER TABLE ... RENAME is still blocked.
|
||||
# Commit transaction to unblock ALTER TABLE ... RENAME.
|
||||
commit;
|
||||
#
|
||||
# Switching to connection 'default'.
|
||||
# Reap ALTER TABLE ... RENAME.
|
||||
@@ -2426,12 +2412,6 @@ set debug_sync='mdl_acquire_lock_wait SIGNAL alter_go';
|
||||
update t1 set c3=c3+1 where c2 = 3;
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
#
|
||||
# Let us check that failure of the above statement has not released
|
||||
# metadata lock on table 't1', i.e. that ALTER TABLE is still blocked.
|
||||
# Unblock ALTER TABLE by commiting transaction and thus releasing
|
||||
# metadata lock on 't1'.
|
||||
commit;
|
||||
#
|
||||
# Switching to connection 'con46273'.
|
||||
# Reap ALTER TABLE.
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user