From: Jon Olav Hauglid Date: August 23 2010 3:42pm Subject: bzr commit into mysql-5.5-bugfixing branch (jon.hauglid:3193) Bug#54332 List-Archive: http://lists.mysql.com/commits/116535 X-Bug: 54332 Message-Id: <201008231545.o7NFj0KM026221@acsinet15.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============4655627416241496110==" --===============4655627416241496110== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/x/mysql-5.5-bugfixing-bug54332/ based on revid:chris.powers@stripped 3193 Jon Olav Hauglid 2010-08-23 Bug #54332 Deadlock with two connections doing LOCK TABLE+INSERT DELAYED The problem was that deadlocks involving INSERT DELAYED were not detected. The reason for this is that two threads are involved in INSERT DELAYED: the connection thread and the handler thread. The connection thread would wait while the handler thread acquired locks and opened the table. In essence, this adds an edge to the wait-for-graph between the connection thread and the handler thread that the deadlock detector is unaware of. Therefore many deadlocks involving INSERT DELAYED were not detected. This patch fixes the problem by having the connection thread acquire the metadata lock the table before starting the handler thread. This allows the deadlock detector to detect any possible deadlocks resulting from trying to acquire a metadata lock the table. If a metadata lock is successfully acquired, the handler thread is started and given a copy of the ticket representing the metadata lock. When the handler thread then tries to lock and open the table, it will find that it already has the metadata lock and therefore not acquire any new metadata locks. Test cases added to delayed.test. modified: mysql-test/r/delayed.result mysql-test/t/delayed.test sql/sql_insert.cc === modified file 'mysql-test/r/delayed.result' --- a/mysql-test/r/delayed.result 2009-12-11 09:39:38 +0000 +++ b/mysql-test/r/delayed.result 2010-08-23 15:42:53 +0000 @@ -345,3 +345,78 @@ CREATE TABLE t1 LIKE t2; ERROR 42S01: Table 't1' already exists DROP TABLE t2; DROP TABLE t1; +# +# Bug#54332 Deadlock with two connections doing LOCK TABLE+INSERT DELAYED +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT); +# Test 1: Using LOCK TABLE +# Connection con1 +LOCK TABLE t1 WRITE; +# Connection default +LOCK TABLE t2 WRITE; +# Sending: +INSERT DELAYED INTO t1 VALUES (1); +# Connection con1 +# Wait until INSERT DELAYED is blocked on table 't1'. +INSERT DELAYED INTO t2 VALUES (1); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +UNLOCK TABLES; +# Connection default +# Reaping: INSERT DELAYED INTO t1 VALUES (1) +UNLOCK TABLES; +# Test 2: Using ALTER TABLE +START TRANSACTION; +SELECT * FROM t1 WHERE a=0; +a +# Connection con1 +# Sending: +ALTER TABLE t1 COMMENT 'test'; +# Connection default +# Wait until ALTER TABLE is blocked on table 't1'. +INSERT DELAYED INTO t1 VALUES (3); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +COMMIT; +# Connection con1 +# Reaping: ALTER TABLE t1 COMMENT 'test' +# Test 3: Using RENAME TABLE +# Connection default +START TRANSACTION; +INSERT INTO t2 VALUES (1); +# Connection con1 +# Sending: +RENAME TABLE t1 to t5, t2 to t4; +# Connection default +# Wait until RENAME TABLE is blocked on table 't1'. +INSERT DELAYED INTO t1 VALUES (4); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +COMMIT; +# Connection con1 +# Reaping: RENAME TABLE t1 to t5, t2 to t4 +# Connection default +# Reverting the renames +RENAME TABLE t5 to t1, t4 to t2; +# Test 4: Two INSERT DELAYED on the same table +START TRANSACTION; +INSERT INTO t2 VALUES (1); +# Connection con2 +LOCK TABLE t1 WRITE, t2 WRITE; +# Connection con1 +# Wait until LOCK TABLE is blocked on table 't2'. +INSERT DELAYED INTO t1 VALUES (5); +# Connection default +# Wait until INSERT DELAYED is blocked on table 't1'. +INSERT DELAYED INTO t1 VALUES (6); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +COMMIT; +# Connection con2 +# Reaping: LOCK TABLE t1 WRITE, t2 WRITE +UNLOCK TABLES; +# Connection con1 +# Reaping: INSERT DELAYED INTO t1 VALUES (5) +# Connection con2 +# Connection con1 +# Connection default +DROP TABLE t1, t2, t3; === modified file 'mysql-test/t/delayed.test' --- a/mysql-test/t/delayed.test 2010-08-06 11:29:37 +0000 +++ b/mysql-test/t/delayed.test 2010-08-23 15:42:53 +0000 @@ -388,3 +388,162 @@ CREATE TABLE t1 LIKE t2; DROP TABLE t2; DROP TABLE t1; + + +--echo # +--echo # Bug#54332 Deadlock with two connections doing LOCK TABLE+INSERT DELAYED +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT); + +--echo # Test 1: Using LOCK TABLE + +--echo # Connection con1 +connect (con1, localhost, root); +LOCK TABLE t1 WRITE; + +--echo # Connection default +connection default; +LOCK TABLE t2 WRITE; +--echo # Sending: +--send INSERT DELAYED INTO t1 VALUES (1) + +--echo # Connection con1 +connection con1; +--echo # Wait until INSERT DELAYED is blocked on table 't1'. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table metadata lock" + AND info = "INSERT DELAYED INTO t1 VALUES (1)"; +--source include/wait_condition.inc +--error ER_LOCK_DEADLOCK +INSERT DELAYED INTO t2 VALUES (1); +UNLOCK TABLES; + +--echo # Connection default +connection default; +--echo # Reaping: INSERT DELAYED INTO t1 VALUES (1) +--reap +UNLOCK TABLES; + +--echo # Test 2: Using ALTER TABLE + +START TRANSACTION; +SELECT * FROM t1 WHERE a=0; + +--echo # Connection con1 +connection con1; +--echo # Sending: +--send ALTER TABLE t1 COMMENT 'test' + +--echo # Connection default +connection default; +--echo # Wait until ALTER TABLE is blocked on table 't1'. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table metadata lock" + AND info = "ALTER TABLE t1 COMMENT 'test'"; +--source include/wait_condition.inc +--error ER_LOCK_DEADLOCK +INSERT DELAYED INTO t1 VALUES (3); +COMMIT; + +--echo # Connection con1 +connection con1; +--echo # Reaping: ALTER TABLE t1 COMMENT 'test' +--reap + +--echo # Test 3: Using RENAME TABLE + +--echo # Connection default +connection default; +START TRANSACTION; +INSERT INTO t2 VALUES (1); + +--echo # Connection con1 +connection con1; +--echo # Sending: +--send RENAME TABLE t1 to t5, t2 to t4 + +--echo # Connection default +connection default; +--echo # Wait until RENAME TABLE is blocked on table 't1'. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table metadata lock" + AND info = "RENAME TABLE t1 to t5, t2 to t4"; +--source include/wait_condition.inc +--error ER_LOCK_DEADLOCK +INSERT DELAYED INTO t1 VALUES (4); +COMMIT; + +--echo # Connection con1 +connection con1; +--echo # Reaping: RENAME TABLE t1 to t5, t2 to t4 +--reap + +--echo # Connection default +connection default; +--echo # Reverting the renames +RENAME TABLE t5 to t1, t4 to t2; + +--echo # Test 4: Two INSERT DELAYED on the same table + +START TRANSACTION; +INSERT INTO t2 VALUES (1); + +--echo # Connection con2 +connect (con2, localhost, root); +--send LOCK TABLE t1 WRITE, t2 WRITE + +--echo # Connection con1 +connection con1; +--echo # Wait until LOCK TABLE is blocked on table 't2'. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table metadata lock" + AND info = "LOCK TABLE t1 WRITE, t2 WRITE"; +--source include/wait_condition.inc +--send INSERT DELAYED INTO t1 VALUES (5) + +--echo # Connection default +connection default; +--echo # Wait until INSERT DELAYED is blocked on table 't1'. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table metadata lock" + AND info = "INSERT DELAYED INTO t1 VALUES (5)"; +--source include/wait_condition.inc +--error ER_LOCK_DEADLOCK +INSERT DELAYED INTO t1 VALUES (6); +COMMIT; + +--echo # Connection con2 +connection con2; +--echo # Reaping: LOCK TABLE t1 WRITE, t2 WRITE +--reap +UNLOCK TABLES; + +--echo # Connection con1 +connection con1; +--echo # Reaping: INSERT DELAYED INTO t1 VALUES (5) +--reap + +--echo # Connection con2 +connection con2; +disconnect con2; +--source include/wait_until_disconnected.inc +--echo # Connection con1 +connection con1; +disconnect con1; +--source include/wait_until_disconnected.inc + +--echo # Connection default +connection default; +DROP TABLE t1, t2, t3; === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2010-08-20 08:24:32 +0000 +++ b/sql/sql_insert.cc 2010-08-23 15:42:53 +0000 @@ -548,10 +548,34 @@ bool open_and_lock_for_insert_delayed(TH DBUG_RETURN(TRUE); } - if (delayed_get_table(thd, table_list)) + /* + In order for the deadlock detector to be able to find any deadlocks + caused by the handler thread locking this table, we take the metadata + lock inside the connection thread. If this goes ok, the ticket is cloned + and added to the list of granted locks held by the handler thread. + */ + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + if (thd->mdl_context.acquire_lock(&table_list->mdl_request, + thd->variables.lock_wait_timeout)) + /* + If a lock can't be acquired, it makes no sense to try normal insert. + Therefore we just abort the statement. + */ DBUG_RETURN(TRUE); - if (table_list->table) + /* + If a lock was acquired above, we should release it after delayed_get_table() + has cloned the ticket for the handler thread. Note that acquire_lock() can + succeed because of a lock already held by the connection. In this case we + should not release it here. + */ + MDL_ticket *table_ticket = mdl_savepoint == thd->mdl_context.mdl_savepoint() ? + NULL: thd->mdl_context.mdl_savepoint(); + + bool error= FALSE; + if (delayed_get_table(thd, table_list)) + error= TRUE; + else if (table_list->table) { /* Open tables used for sub-selects or in stored functions, will also @@ -560,16 +584,30 @@ bool open_and_lock_for_insert_delayed(TH if (open_and_lock_tables(thd, table_list->next_global, TRUE, 0)) { end_delayed_insert(thd); - DBUG_RETURN(TRUE); + error= TRUE; + } + else + { + /* + First table was not processed by open_and_lock_tables(), + we need to set updatability flag "by hand". + */ + if (!table_list->derived && !table_list->view) + table_list->updatable= 1; // usual table } - /* - First table was not processed by open_and_lock_tables(), - we need to set updatability flag "by hand". - */ - if (!table_list->derived && !table_list->view) - table_list->updatable= 1; // usual table - DBUG_RETURN(FALSE); } + + if (table_ticket) + thd->mdl_context.release_lock(table_ticket); + /* + Clone_ticket() in delayed_get_table() causes TABLE_LIST::MDL_REQUEST::ticket + to be overwritten with the cloned ticket. Reset the ticket here in case + we end up having to use normal insert. + */ + table_list->mdl_request.ticket= NULL; + + if (error || table_list->table) + DBUG_RETURN(error); #endif /* * This is embedded library and we don't have auxiliary @@ -2025,6 +2063,20 @@ bool delayed_get_table(THD *thd, TABLE_L /* Replace volatile strings with local copies */ di->table_list.alias= di->table_list.table_name= di->thd.query(); di->table_list.db= di->thd.db; + + /* + Clone the ticket representing the lock on the target table for + the insert and add it to the list of granted metadata locks held by + the handler thread. This is safe since the handler thread is + not holding nor waiting on any metadata locks. + */ + if (di->thd.mdl_context.clone_ticket(&table_list->mdl_request)) + { + delete di; + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + goto end_create; + } + di->lock(); mysql_mutex_lock(&di->mutex); if ((error= mysql_thread_create(key_thread_delayed_insert, @@ -2036,6 +2088,7 @@ bool delayed_get_table(THD *thd, TABLE_L error)); mysql_mutex_unlock(&di->mutex); di->unlock(); + di->thd.mdl_context.release_lock(table_list->mdl_request.ticket); delete di; my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATALERROR), error); goto end_create; --===============4655627416241496110== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jon.hauglid@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jon.hauglid@stripped # target_branch: file:///export/home/x/mysql-5.5-bugfixing-bug54332/ # testament_sha1: 4d43d6da6c1998a855bf602fb6bff3a47652d484 # timestamp: 2010-08-23 17:42:56 +0200 # source_branch: file:///export/home/x/mysql-5.5-runtime/ # base_revision_id: chris.powers@stripped\ # kz9nw6264sxpm6q4 # # Begin bundle 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 X1o= --===============4655627416241496110==--