mariadb/mysql-test
Dmitry Lenev afd15c43a9 Implement new type-of-operation-aware metadata locks.
Add a wait-for graph based deadlock detector to the
MDL subsystem.

Fixes bug #46272 "MySQL 5.4.4, new MDL: unnecessary deadlock" and
bug #37346 "innodb does not detect deadlock between update and
alter table".

The first bug manifested itself as an unwarranted abort of a
transaction with ER_LOCK_DEADLOCK error by a concurrent ALTER
statement, when this transaction tried to repeat use of a
table, which it has already used in a similar fashion before
ALTER started.

The second bug showed up as a deadlock between table-level
locks and InnoDB row locks, which was "detected" only after
innodb_lock_wait_timeout timeout.

A transaction would start using the table and modify a few
rows.
Then ALTER TABLE would come in, and start copying rows
into a temporary table. Eventually it would stumble on
the modified records and get blocked on a row lock.
The first transaction would try to do more updates, and get
blocked on thr_lock.c lock.
This situation of circular wait would only get resolved
by a timeout.

Both these bugs stemmed from inadequate solutions to the
problem of deadlocks occurring between different
locking subsystems.

In the first case we tried to avoid deadlocks between metadata
locking and table-level locking subsystems, when upgrading shared
metadata lock to exclusive one.
Transactions holding the shared lock on the table and waiting for
some table-level lock used to be aborted too aggressively.

We also allowed ALTER TABLE to start in presence of transactions
that modify the subject table. ALTER TABLE acquires
TL_WRITE_ALLOW_READ lock at start, and that block all writes
against the table (naturally, we don't want any writes to be lost
when switching the old and the new table). TL_WRITE_ALLOW_READ
lock, in turn, would block the started transaction on thr_lock.c
lock, should they do more updates. This, again, lead to the need
to abort such transactions.

The second bug occurred simply because we didn't have any
mechanism to detect deadlocks between the table-level locks
in thr_lock.c and row-level locks in InnoDB, other than
innodb_lock_wait_timeout.

This patch solves both these problems by moving lock conflicts
which are causing these deadlocks into the metadata locking
subsystem, thus making it possible to avoid or detect such
deadlocks inside MDL.

To do this we introduce new type-of-operation-aware metadata
locks, which allow MDL subsystem to know not only the fact that
transaction has used or is going to use some object but also what
kind of operation it has carried out or going to carry out on the
object.

This, along with the addition of a special kind of upgradable
metadata lock, allows ALTER TABLE to wait until all
transactions which has updated the table to go away.
This solves the second issue.
Another special type of upgradable metadata lock is acquired
by LOCK TABLE WRITE. This second lock type allows to solve the
first issue, since abortion of table-level locks in event of
DDL under LOCK TABLES becomes also unnecessary.

Below follows the list of incompatible changes introduced by
this patch:

- From now on, ALTER TABLE and CREATE/DROP TRIGGER SQL (i.e. those
  statements that acquire TL_WRITE_ALLOW_READ lock)
  wait for all transactions which has *updated* the table to
  complete.

- From now on, LOCK TABLES ... WRITE, REPAIR/OPTIMIZE TABLE
  (i.e. all statements which acquire TL_WRITE table-level lock) wait
  for all transaction which *updated or read* from the table
  to complete.
  As a consequence, innodb_table_locks=0 option no longer applies
  to LOCK TABLES ... WRITE.

- DROP DATABASE, DROP TABLE, RENAME TABLE no longer abort
  statements or transactions which use tables being dropped or
  renamed, and instead wait for these transactions to complete.

- Since LOCK TABLES WRITE now takes a special metadata lock,
  not compatible with with reads or writes against the subject table
  and transaction-wide, thr_lock.c deadlock avoidance algorithm
  that used to ensure absence of deadlocks between LOCK TABLES
  WRITE and other statements is no longer sufficient, even for
  MyISAM. The wait-for graph based deadlock detector of MDL
  subsystem may sometimes be necessary and is involved. This may
  lead to ER_LOCK_DEADLOCK error produced for multi-statement
  transactions even if these only use MyISAM:

  session 1:         session 2:
  begin;

  update t1 ...      lock table t2 write, t1 write;
                     -- gets a lock on t2, blocks on t1

  update t2 ...
  (ER_LOCK_DEADLOCK)

- Finally,  support of LOW_PRIORITY option for LOCK TABLES ... WRITE
  was abandoned.
  LOCK TABLE ... LOW_PRIORITY WRITE from now on has the same
  priority as the usual LOCK TABLE ... WRITE.
  SELECT HIGH PRIORITY no longer trumps LOCK TABLE ... WRITE  in
  the wait queue.

- We do not take upgradable metadata locks on implicitly
  locked tables. So if one has, say, a view v1 that uses
  table t1, and issues:
  LOCK TABLE v1 WRITE;
  FLUSH TABLE t1; -- (or just 'FLUSH TABLES'),
  an error is produced.
  In order to be able to perform DDL on a table under LOCK TABLES,
  the table must be locked explicitly in the LOCK TABLES list.
2010-02-01 14:43:06 +03:00
..
collections Manual resolving for the following files 2009-12-01 21:07:18 +02:00
extra Merge next-mr -> next-4284. 2009-12-15 22:59:07 +03:00
include Implement new type-of-operation-aware metadata locks. 2010-02-01 14:43:06 +03:00
lib Merge next-mr -> next-4284. 2009-12-16 11:33:54 +03:00
r Implement new type-of-operation-aware metadata locks. 2010-02-01 14:43:06 +03:00
std_data Backporting Bug#37129 LDML lacks <i> rule 2009-11-09 13:45:40 +04:00
suite Implement new type-of-operation-aware metadata locks. 2010-02-01 14:43:06 +03:00
t Implement new type-of-operation-aware metadata locks. 2010-02-01 14:43:06 +03:00
Makefile.am
mysql-stress-test.pl
mysql-test-run.pl Auto merge from 5.1-rep-semisync 2009-12-05 10:28:53 +08:00
purify.supp
README
README.gcov
README.stress
valgrind.supp

This directory contains a test suite for the MySQL daemon. To run
the currently existing test cases, simply execute ./mysql-test-run in
this directory. It will fire up the newly built mysqld and test it.

Note that you do not have to have to do "make install", and you could
actually have a co-existing MySQL installation. The tests will not
conflict with it.

All tests must pass. If one or more of them fail on your system, please
read the following manual section for instructions on how to report the
problem:

http://dev.mysql.com/doc/mysql/en/mysql-test-suite.html

If you want to use an already running MySQL server for specific tests,
use the --extern option to mysql-test-run. Please note that in this mode,
the test suite expects you to provide the names of the tests to run.
For example, here is the command to run the "alias" and "analyze" tests
with an external server:

mysql-test-run --extern alias analyze

To match your setup, you might also need to provide --socket, --user, and
other relevant options.

With no test cases named on the command line, mysql-test-run falls back
to the normal "non-extern" behavior. The reason for this is that some
tests cannot run with an external server.


You can create your own test cases. To create a test case, create a new
file in the t subdirectory using a text editor. The file should have a .test
extension. For example:

 xemacs t/test_case_name.test

 In the file, put a set of SQL statements that create some tables,
 load test data, and run some queries to manipulate it.

 We would appreciate it if you name your test tables t1, t2, t3 ... (to not
 conflict too much with existing tables).

 Your test should begin by dropping the tables you are going to create and
 end by dropping them again.  This ensures that you can run the test over
 and over again.
 
 If you are using mysqltest commands (like result file names) in your
 test case, you should create the result file as follows:

 mysql-test-run --record test_case_name

 or

 mysqltest --record < t/test_case_name.test

 If you only have a simple test cases consisting of SQL statements and
 comments, you can create the test case in one of the following ways:

 mysql-test-run --record test_case_name

 mysql test < t/test_case_name.test > r/test_case_name.result

 mysqltest --record --record-file=r/test_case_name.result < t/test_case_name.test

 When this is done, take a look at r/test_case_name.result
 - If the result is incorrect, you have found a bug. In this case, you should
   edit the test result to the correct results so that we can verify
   that the bug is corrected in future releases.

To submit your test case, put your .test file and .result file(s) into
a tar.gz archive, add a README that explains the problem, ftp the 
archive to ftp://support.mysql.com/pub/mysql/secret/ and send a mail
to bugs@lists.mysql.com