1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Implementation of simple deadlock detection for metadata locks.

This change is supposed to reduce number of ER_LOCK_DEADLOCK
errors which occur when multi-statement transaction encounters
conflicting metadata lock in cases when waiting is possible.

The idea is not to fail ER_LOCK_DEADLOCK error immediately when
we encounter conflicting metadata lock. Instead we release all
metadata locks acquired by current statement and start to wait
until conflicting lock go away. To avoid deadlocks we use simple
empiric which aborts waiting with ER_LOCK_DEADLOCK error if it
turns out that somebody is waiting for metadata locks owned by
this transaction.

This patch also fixes bug #46273 "MySQL 5.4.4 new MDL: Bug#989
is not fully fixed in case of ALTER".

The bug was that concurrent execution of UPDATE or MULTI-UPDATE
statement as a part of multi-statement transaction that already
has used table being updated and ALTER TABLE statement might have
resulted of loss of isolation between this transaction and ALTER
TABLE statement, which manifested itself as changes performed by
ALTER TABLE becoming visible in transaction and wrong binary log
order as a consequence.

This problem occurred when UPDATE or MULTI-UPDATE's wait in
mysql_lock_tables() call was aborted due to metadata lock
upgrade performed by concurrent ALTER TABLE. After such abort all
metadata locks held by transaction were released but transaction
silently continued to be executed as if nothing has happened.

We solve this problem by changing our code not to release all
locks in such case. Instead we release only locks which were
acquired by current statement and then try to reacquire them
by restarting open/lock tables process. We piggyback on simple
deadlock detector implementation since this change has to be
done anyway for it.
This commit is contained in:
Dmitry Lenev
2009-12-30 20:53:30 +03:00
parent cd6fbffc38
commit 236539b471
17 changed files with 1189 additions and 262 deletions

View File

@ -745,12 +745,13 @@ drop table t1;
handler t1 read a next;
ERROR 42S02: Unknown table 't1' in HANDLER
drop table if exists t1;
create table t1 (a int);
create table t1 (a int, key a (a));
insert into t1 values (1);
handler t1 open;
alter table t1 engine=memory;
handler t1 read a next;
ERROR HY000: Table storage engine for 't1' doesn't have this option
a
1
handler t1 close;
drop table t1;
USE information_schema;
@ -1002,9 +1003,9 @@ a
lock table t2 read;
# --> connection con2
# Sending:
drop table t2;
rename table t2 to t3, t1 to t2, t3 to t1;
# --> connection con1
# Waiting for 'drop table t2' to get blocked...
# Waiting for 'rename table ...' to get blocked...
# --> connection default
handler t2 open;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
@ -1012,23 +1013,24 @@ select * from t2;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
handler t1 open;
commit;
handler t2 open;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
handler t1 close;
# --> connection con1
unlock tables;
# --> connection con2
# Reaping 'drop table t2'...
# Reaping 'rename table ...'...
# --> connection default
handler t1 open;
handler t1 read a prev;
a
5
handler t1 close;
drop table t2;
#
# Likewise, this doesn't require a multi-statement transaction.
# ER_LOCK_DEADLOCK is also produced when we have an open
# HANDLER and try to acquire locks for a single statement.
# Originally there was a deadlock error in this test.
# With implementation of deadlock detector
# we no longer deadlock, but block and wait on a lock.
# The HANDLER is auto-closed as soon as the connection
# sees a pending conflicting lock against it.
#
create table t2 (a int, key a (a));
handler t1 open;
@ -1040,13 +1042,16 @@ drop table t2;
# --> connection con1
# Waiting for 'drop table t2' to get blocked...
# --> connection default
# Sending 'select * from t2'
select * from t2;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
# --> connection con1
# Waiting for 'select * from t2' to get blocked...
unlock tables;
# --> connection con2
# Reaping 'drop table t2'...
# --> connection default
# Reaping 'select * from t2'
ERROR 42S02: Table 'test.t2' doesn't exist
handler t1 close;
#
# ROLLBACK TO SAVEPOINT releases transactional locks,