diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index e03e83efac2..14f1dd97830 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -186,6 +186,14 @@ INSERT INTO global_suppressions VALUES (": The MySQL server is running with the --secure-backup-file-priv option so it cannot execute this statement"), ("Slave: Unknown table 't1' Error_code: 1051"), + /* + BUG#42147 - Concurrent DML and LOCK TABLE ... READ for InnoDB + table cause warnings in errlog + Note: This is a temporary suppression until Bug#42147 can be + fixed properly. See bug page for more information. + */ + ("Found lock of type 6 that is write and read locked"), + ("THE_LAST_SUPPRESSION")|| diff --git a/mysql-test/lib/v1/mtr_report.pl b/mysql-test/lib/v1/mtr_report.pl index 3c78c3ca064..36aba983c34 100644 --- a/mysql-test/lib/v1/mtr_report.pl +++ b/mysql-test/lib/v1/mtr_report.pl @@ -376,6 +376,9 @@ sub mtr_report_stats ($) { /Slave: Can't DROP 'c7'.* 1091/ or /Slave: Key column 'c6'.* 1072/ or + # Warnings generated until bug#42147 is properly resolved + /Found lock of type 6 that is write and read locked/ or + # rpl_idempotency.test produces warnings for the slave. ($testname eq 'rpl.rpl_idempotency' and (/Slave: Can\'t find record in \'t1\' Error_code: 1032/ or diff --git a/mysql-test/r/innodb_mysql_lock.result b/mysql-test/r/innodb_mysql_lock.result index 147267d5550..374f67358eb 100644 --- a/mysql-test/r/innodb_mysql_lock.result +++ b/mysql-test/r/innodb_mysql_lock.result @@ -21,4 +21,36 @@ INSERT INTO t1 VALUES (2); ERROR 40001: Deadlock found when trying to get lock; try restarting transaction # Cleanup commit; +set @@autocommit=1; commit; +set @@autocommit=1; +set @@autocommit=1; +# +# Bug #42147 Concurrent DML and LOCK TABLE ... READ for InnoDB +# table cause warnings in errlog +# +# +# Note that this test for now relies on a global suppression of +# the warning "Found lock of type 6 that is write and read locked" +# This suppression rule can be removed once Bug#42147 is properly +# fixed. See bug page for more info. +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i INT) engine= innodb; +# Connection 2 +# Get user-level lock +SELECT get_lock('bug42147_lock', 60); +get_lock('bug42147_lock', 60) +1 +# Connection 1 +INSERT INTO t1 SELECT get_lock('bug42147_lock', 60); +# Connection 2 +LOCK TABLES t1 READ; +SELECT release_lock('bug42147_lock'); +release_lock('bug42147_lock') +1 +# Connection 1 +# Connection 2 +UNLOCK TABLES; +# Connection 1 +DROP TABLE t1; diff --git a/mysql-test/t/innodb_mysql_lock.test b/mysql-test/t/innodb_mysql_lock.test index daee94bedb5..c8c38cd1ab1 100644 --- a/mysql-test/t/innodb_mysql_lock.test +++ b/mysql-test/t/innodb_mysql_lock.test @@ -1,5 +1,8 @@ -- source include/have_innodb.inc +# Save the initial number of concurrent sessions. +--source include/count_sessions.inc + --echo # --echo # Bug #22876 Four-way deadlock --echo # @@ -51,8 +54,68 @@ INSERT INTO t1 VALUES (2); connection con2; --reap commit; +set @@autocommit=1; connection con1; commit; +set @@autocommit=1; connection con3; --reap +set @@autocommit=1; connection default; + +disconnect con1; +disconnect con3; + +--echo # +--echo # Bug #42147 Concurrent DML and LOCK TABLE ... READ for InnoDB +--echo # table cause warnings in errlog +--echo # + +--echo # +--echo # Note that this test for now relies on a global suppression of +--echo # the warning "Found lock of type 6 that is write and read locked" +--echo # This suppression rule can be removed once Bug#42147 is properly +--echo # fixed. See bug page for more info. +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (i INT) engine= innodb; + +--echo # Connection 2 +--echo # Get user-level lock +connection con2; +SELECT get_lock('bug42147_lock', 60); + +--echo # Connection 1 +connection default; +--send INSERT INTO t1 SELECT get_lock('bug42147_lock', 60) + +--echo # Connection 2 +connection con2; +let $wait_condition= + SELECT COUNT(*) > 0 FROM information_schema.processlist + WHERE state = 'User lock' + AND info = 'INSERT INTO t1 SELECT get_lock(\'bug42147_lock\', 60)'; +--source include/wait_condition.inc +LOCK TABLES t1 READ; +SELECT release_lock('bug42147_lock'); + +--echo # Connection 1 +connection default; +--reap + +--echo # Connection 2 +connection con2; +UNLOCK TABLES; + +--echo # Connection 1 +connection default; +disconnect con2; +DROP TABLE t1; + +# Check that all connections opened by test cases in this file are really +# gone so execution of other tests won't be affected by their presence. +--source include/wait_until_count_sessions.inc diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 6433c04a96f..a3f3e9ee080 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -540,13 +540,31 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, /* Request for READ lock */ if (lock->write.data) { - /* We can allow a read lock even if there is already a write lock - on the table in one the following cases: - - This thread alread have a write lock on the table - - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED - and the read lock is TL_READ_HIGH_PRIORITY or TL_READ - - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE - and the read lock is not TL_READ_NO_INSERT + /* + We can allow a read lock even if there is already a + write lock on the table if they are owned by the same + thread or if they satisfy the following lock + compatibility matrix: + + Request + /------- + H|++++ WRITE_ALLOW_WRITE + e|+++- WRITE_ALLOW_READ + l|+++- WRITE_CONCURRENT_INSERT + d|++++ WRITE_DELAYED + |||| + |||\= READ_NO_INSERT + ||\ = READ_HIGH_PRIORITY + |\ = READ_WITH_SHARED_LOCKS + \ = READ + + + = Request can be satisified. + - = Request cannot be satisified. + + READ_NO_INSERT and WRITE_ALLOW_WRITE should in principle + be incompatible. However this will cause starvation of + LOCK TABLE READ in InnoDB under high write load. + See Bug#42147 for more information. */ DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx",