From 72e978828edb6b6cc045e6c728747dafd46b8732 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Fri, 3 Apr 2009 16:11:54 -0300 Subject: Bug#43230: SELECT ... FOR UPDATE can hang with FLUSH TABLES WITH READ LOCK indefinitely The problem is that a SELECT .. FOR UPDATE statement might open a table and later wait for a impeding global read lock without noticing whether it is holding a table that is being waited upon the the flush phase of the process that took the global read lock. The same problem also affected the following statements: LOCK TABLES .. WRITE UPDATE .. SET (update and multi-table update) TRUNCATE TABLE .. LOAD DATA .. The solution is to make the above statements wait for a impending global read lock before opening the tables. If there is no impending global read lock, the statement raises a temporary protection against global read locks and progresses smoothly towards completion. Important notice: the patch does not try to address all possible cases, only those which are common and can be fixed unintrusively enough for 5.0. mysql-test/r/lock_multi.result: Add test case result for Bug#43230 mysql-test/t/lock_multi.test: Add test case for Bug#43230 sql/sql_lex.cc: Initialize flag. sql/sql_lex.h: Add a flag to the lexer. sql/sql_parse.cc: Wait for the global read lock is a write lock is going to be taken. The wait is done before opening tables. sql/sql_yacc.yy: Protect against the GRL if its a SELECT .. FOR UPDATE or LOCK TABLES .. WRITE statement. --- sql/sql_lex.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sql/sql_lex.h') diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 9f020f4adc5..3e762581e04 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1176,6 +1176,22 @@ typedef struct st_lex : public Query_tables_list bool escape_used; + /* + Special case for SELECT .. FOR UPDATE and LOCK TABLES .. WRITE. + + Protect from a impending GRL as otherwise the thread might deadlock + if it starts waiting for the GRL in mysql_lock_tables. + + The protection is needed because there is a race between setting + the global read lock and waiting for all open tables to be closed. + The problem is a circular wait where a thread holding "old" open + tables will wait for the global read lock to be released while the + thread holding the global read lock will wait for all "old" open + tables to be closed -- the flush part of flush tables with read + lock. + */ + bool protect_against_global_read_lock; + st_lex(); virtual ~st_lex() -- cgit v1.2.1