Merge lp:~sergei.glushchenko/percona-server/ST-28169-Bug1127008-5.6 into lp:percona-server/5.6

Proposed by Sergei Glushchenko
Status: Work in progress
Proposed branch: lp:~sergei.glushchenko/percona-server/ST-28169-Bug1127008-5.6
Merge into: lp:percona-server/5.6
Diff against target: 396 lines (+207/-21)
11 files modified
Percona-Server/mysql-test/r/create.result (+28/-0)
Percona-Server/mysql-test/r/create_delayed.result (+3/-0)
Percona-Server/mysql-test/t/create.test (+25/-0)
Percona-Server/mysql-test/t/create_delayed.test (+34/-0)
Percona-Server/sql/mdl.cc (+5/-1)
Percona-Server/sql/sql_base.cc (+92/-16)
Percona-Server/sql/sql_base.h (+2/-1)
Percona-Server/sql/sql_db.cc (+1/-1)
Percona-Server/sql/sql_insert.cc (+4/-0)
Percona-Server/sql/sql_parse.cc (+8/-1)
Percona-Server/sql/sql_table.cc (+5/-1)
To merge this branch: bzr merge lp:~sergei.glushchenko/percona-server/ST-28169-Bug1127008-5.6
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Needs Fixing
Review via email: mp+149501@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Same comments as for 5.5. And I'm not sure we should submit any 5.6 MPs until we fix our 5.6 tree so we can follow the normal merge workflow.

review: Needs Fixing

Unmerged revisions

316. By Sergei Glushchenko

Port of fix for bug 1127008 from 5.5 series

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Percona-Server/mysql-test/r/create.result'
2--- Percona-Server/mysql-test/r/create.result 2013-01-18 04:53:12 +0000
3+++ Percona-Server/mysql-test/r/create.result 2013-02-20 09:38:26 +0000
4@@ -2625,3 +2625,31 @@
5 ERROR 42000: Identifier name 't01234567890123456789012345678901234567890123456789012345678901234567890123456789' is too long
6 CREATE DATABASE t01234567890123456789012345678901234567890123456789012345678901234567890123456789;
7 ERROR 42000: Identifier name 't01234567890123456789012345678901234567890123456789012345678901234567890123456789' is too long
8+#
9+# Checking that CREATE IF NOT EXISTS is not blocked by running SELECT
10+#
11+create table t1 (a int, b int) engine=myisam;
12+create table t2 (a int, b int) engine=myisam;
13+insert into t1 values (1,1);
14+lock tables t1 read;
15+set @@lock_wait_timeout=5;
16+create table if not exists t1 (a int, b int);
17+Warnings:
18+Note 1050 Table 't1' already exists
19+create table if not exists t1 (a int, b int) select 2,2;
20+Warnings:
21+Note 1050 Table 't1' already exists
22+create table if not exists t1 like t2;
23+Warnings:
24+Note 1050 Table 't1' already exists
25+create table t1 (a int, b int);
26+ERROR 42S01: Table 't1' already exists
27+create table t1 (a int, b int) select 2,2;
28+ERROR 42S01: Table 't1' already exists
29+create table t1 like t2;
30+ERROR 42S01: Table 't1' already exists
31+select * from t1;
32+a b
33+1 1
34+unlock tables;
35+drop table t1,t2;
36
37=== added file 'Percona-Server/mysql-test/r/create_delayed.result'
38--- Percona-Server/mysql-test/r/create_delayed.result 1970-01-01 00:00:00 +0000
39+++ Percona-Server/mysql-test/r/create_delayed.result 2013-02-20 09:38:26 +0000
40@@ -0,0 +1,3 @@
41+drop table if exists t1;
42+Starting test
43+# All done
44
45=== modified file 'Percona-Server/mysql-test/t/create.test'
46--- Percona-Server/mysql-test/t/create.test 2012-08-22 01:40:20 +0000
47+++ Percona-Server/mysql-test/t/create.test 2013-02-20 09:38:26 +0000
48@@ -2096,3 +2096,28 @@
49 CREATE TABLE t01234567890123456789012345678901234567890123456789012345678901234567890123456789(a int);
50 --error ER_TOO_LONG_IDENT
51 CREATE DATABASE t01234567890123456789012345678901234567890123456789012345678901234567890123456789;
52+
53+--echo #
54+--echo # Checking that CREATE IF NOT EXISTS is not blocked by running SELECT
55+--echo #
56+
57+create table t1 (a int, b int) engine=myisam;
58+create table t2 (a int, b int) engine=myisam;
59+insert into t1 values (1,1);
60+lock tables t1 read;
61+connect (user1,localhost,root,,test);
62+set @@lock_wait_timeout=5;
63+create table if not exists t1 (a int, b int);
64+create table if not exists t1 (a int, b int) select 2,2;
65+create table if not exists t1 like t2;
66+--error ER_TABLE_EXISTS_ERROR
67+create table t1 (a int, b int);
68+--error ER_TABLE_EXISTS_ERROR
69+create table t1 (a int, b int) select 2,2;
70+--error ER_TABLE_EXISTS_ERROR
71+create table t1 like t2;
72+disconnect user1;
73+connection default;
74+select * from t1;
75+unlock tables;
76+drop table t1,t2;
77
78=== added file 'Percona-Server/mysql-test/t/create_delayed.test'
79--- Percona-Server/mysql-test/t/create_delayed.test 1970-01-01 00:00:00 +0000
80+++ Percona-Server/mysql-test/t/create_delayed.test 2013-02-20 09:38:26 +0000
81@@ -0,0 +1,34 @@
82+#
83+# Ensure that INSERT DELAYED works with CREATE TABLE on existing table
84+#
85+
86+-- source include/big_test.inc
87+
88+--disable_warnings
89+drop table if exists t1;
90+--enable_warnings
91+
92+--disable_query_log
93+--disable_result_log
94+
95+--let $run=1000
96+
97+--echo Starting test
98+
99+while ($run)
100+{
101+# --echo # $run attempts left...
102+ CREATE TABLE t1 ( f1 INTEGER AUTO_INCREMENT, PRIMARY KEY (f1)) ENGINE=MyISAM;
103+ INSERT DELAYED t1 VALUES (4);
104+--error ER_TABLE_EXISTS_ERROR
105+ CREATE TABLE t1 AS SELECT 1 AS f1;
106+
107+ REPLACE DELAYED t1 VALUES (5);
108+ DROP TABLE t1;
109+--dec $run
110+}
111+
112+--enable_query_log
113+--enable_result_log
114+
115+--echo # All done
116
117=== modified file 'Percona-Server/sql/mdl.cc'
118--- Percona-Server/sql/mdl.cc 2012-12-04 08:24:59 +0000
119+++ Percona-Server/sql/mdl.cc 2013-02-20 09:38:26 +0000
120@@ -2200,7 +2200,11 @@
121 */
122 m_wait.reset_status();
123
124- if (lock->needs_notification(ticket))
125+ /*
126+ Don't break conflicting locks if timeout is 0 as 0 is used
127+ To check if there is any conflicting locks...
128+ */
129+ if (lock->needs_notification(ticket) && lock_wait_timeout)
130 lock->notify_conflicting_locks(this);
131
132 mysql_prlock_unlock(&lock->m_rwlock);
133
134=== modified file 'Percona-Server/sql/sql_base.cc'
135--- Percona-Server/sql/sql_base.cc 2013-02-12 07:47:19 +0000
136+++ Percona-Server/sql/sql_base.cc 2013-02-20 09:38:26 +0000
137@@ -2271,10 +2271,11 @@
138 Check that table exists in table definition cache, on disk
139 or in some storage engine.
140
141- @param thd Thread context
142- @param table Table list element
143- @param[out] exists Out parameter which is set to TRUE if table
144- exists and to FALSE otherwise.
145+ @param thd Thread context
146+ @param table Table list element
147+ @param fast_check Check only if share or .frm file exists
148+ @param[out] exists Out parameter which is set to TRUE if table
149+ exists and to FALSE otherwise.
150
151 @note This function acquires LOCK_open internally.
152
153@@ -2286,7 +2287,8 @@
154 @retval FALSE No error. 'exists' out parameter set accordingly.
155 */
156
157-bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
158+bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool fast_check,
159+ bool *exists)
160 {
161 char path[FN_REFLEN + 1];
162 TABLE_SHARE *share;
163@@ -2294,7 +2296,8 @@
164
165 *exists= TRUE;
166
167- DBUG_ASSERT(thd->mdl_context.
168+ DBUG_ASSERT(fast_check ||
169+ thd->mdl_context.
170 is_lock_owner(MDL_key::TABLE, table->db,
171 table->table_name, MDL_SHARED));
172
173@@ -2311,6 +2314,12 @@
174 if (!access(path, F_OK))
175 goto end;
176
177+ if (fast_check)
178+ {
179+ *exists= FALSE;
180+ goto end;
181+ }
182+
183 /* .FRM file doesn't exist. Check if some engine can provide it. */
184 if (ha_check_if_table_exists(thd, table->db, table->table_name, exists))
185 {
186@@ -2819,7 +2828,7 @@
187 {
188 bool exists;
189
190- if (check_if_table_exists(thd, table_list, &exists))
191+ if (check_if_table_exists(thd, table_list, 0, &exists))
192 DBUG_RETURN(TRUE);
193
194 if (!exists)
195@@ -4688,7 +4697,18 @@
196 open, see open_table() description for details.
197
198 @retval FALSE Success.
199- @retval TRUE Failure (e.g. connection was killed)
200+ @retval TRUE Failure (e.g. connection was killed) or table existed
201+ for a CREATE TABLE.
202+
203+ @notes
204+ In case of CREATE TABLE we avoid a wait for tables that are in use
205+ by first trying to do a meta data lock with timeout == 0. If we get a
206+ timeout we will check if table exists (it should) and retry with
207+ normal timeout if it didn't exists.
208+ Note that for CREATE TABLE IF EXISTS we only generate a warning
209+ but still return TRUE (to abort the calling open_table() function).
210+ On must check THD->is_error() if one wants to distinguish between warning
211+ and error.
212 */
213
214 bool
215@@ -4700,6 +4720,10 @@
216 TABLE_LIST *table;
217 MDL_request global_request;
218 Hash_set<TABLE_LIST, schema_set_get_key> schema_set;
219+ ulong org_lock_wait_timeout= lock_wait_timeout;
220+ /* Check if we are using CREATE TABLE ... IF NOT EXISTS */
221+ bool create_table;
222+ Dummy_error_handler error_handler;
223
224 DBUG_ASSERT(!thd->locked_tables_mode);
225
226@@ -4726,8 +4750,14 @@
227 mdl_requests.push_front(&table->mdl_request);
228 }
229
230- if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
231- ! mdl_requests.is_empty())
232+ if (mdl_requests.is_empty())
233+ return FALSE;
234+
235+ /* Check if CREATE TABLE IF NOT EXISTS was used */
236+ create_table= (tables_start && tables_start->open_strategy ==
237+ TABLE_LIST::OPEN_IF_EXISTS);
238+
239+ if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
240 {
241 /*
242 Scoped locks: Take intention exclusive locks on all involved
243@@ -4755,12 +4785,58 @@
244 global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
245 MDL_STATEMENT);
246 mdl_requests.push_front(&global_request);
247- }
248-
249- if (thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout))
250- return TRUE;
251-
252- return FALSE;
253+
254+ if (create_table)
255+ lock_wait_timeout= 0; // Don't wait for timeout
256+ }
257+
258+ for (;;)
259+ {
260+ bool exists= TRUE;
261+ bool res;
262+
263+ if (create_table)
264+ thd->push_internal_handler(&error_handler); // Avoid warnings & errors
265+ res= thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout);
266+ if (create_table)
267+ thd->pop_internal_handler();
268+ if (!res)
269+ return FALSE; // Got locks
270+
271+ if (!create_table)
272+ return TRUE; // Return original error
273+
274+ /*
275+ We come here in the case of lock timeout when executing
276+ CREATE TABLE IF NOT EXISTS.
277+ Verify that table really exists (it should as we got a lock conflict)
278+ */
279+ if (check_if_table_exists(thd, tables_start, 1, &exists))
280+ return TRUE; // Should never happen
281+ if (exists)
282+ {
283+ if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
284+ {
285+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
286+ ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
287+ tables_start->table_name);
288+ }
289+ else
290+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name);
291+ return TRUE;
292+ }
293+ /* purecov: begin inspected */
294+ /*
295+ We got error from acquire_locks but table didn't exists.
296+ In theory this should never happen, except maybe in
297+ CREATE or DROP DATABASE scenario.
298+ We play safe and restart the original acquire_locks with the
299+ original timeout
300+ */
301+ create_table= 0;
302+ lock_wait_timeout= org_lock_wait_timeout;
303+ /* purecov: end */
304+ }
305 }
306
307
308
309=== modified file 'Percona-Server/sql/sql_base.h'
310--- Percona-Server/sql/sql_base.h 2013-02-12 07:47:19 +0000
311+++ Percona-Server/sql/sql_base.h 2013-02-20 09:38:26 +0000
312@@ -300,7 +300,8 @@
313 const char *table_name,
314 bool no_error);
315 void mark_tmp_table_for_reuse(TABLE *table);
316-bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists);
317+bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool fast_check,
318+ bool *exists);
319
320 extern Item **not_found_item;
321 extern Field *not_found_field;
322
323=== modified file 'Percona-Server/sql/sql_db.cc'
324--- Percona-Server/sql/sql_db.cc 2013-02-12 07:47:19 +0000
325+++ Percona-Server/sql/sql_db.cc 2013-02-20 09:38:26 +0000
326@@ -958,7 +958,7 @@
327 bool exists;
328
329 // Only write drop table to the binlog for tables that no longer exist.
330- if (check_if_table_exists(thd, tbl, &exists))
331+ if (check_if_table_exists(thd, tbl, 0, &exists))
332 {
333 error= true;
334 goto exit;
335
336=== modified file 'Percona-Server/sql/sql_insert.cc'
337--- Percona-Server/sql/sql_insert.cc 2013-01-18 04:53:12 +0000
338+++ Percona-Server/sql/sql_insert.cc 2013-02-20 09:38:26 +0000
339@@ -2896,8 +2896,12 @@
340 set_timespec(abstime, delayed_insert_timeout);
341
342 /* Information for pthread_kill */
343+ mysql_mutex_unlock(&di->mutex);
344+ mysql_mutex_lock(&di->thd.mysys_var->mutex);
345 di->thd.mysys_var->current_mutex= &di->mutex;
346 di->thd.mysys_var->current_cond= &di->cond;
347+ mysql_mutex_unlock(&di->thd.mysys_var->mutex);
348+ mysql_mutex_lock(&di->mutex);
349 THD_STAGE_INFO(&(di->thd), stage_waiting_for_insert);
350
351 DBUG_PRINT("info",("Waiting for someone to insert rows"));
352
353=== modified file 'Percona-Server/sql/sql_parse.cc'
354--- Percona-Server/sql/sql_parse.cc 2013-02-12 07:47:19 +0000
355+++ Percona-Server/sql/sql_parse.cc 2013-02-20 09:38:26 +0000
356@@ -2924,7 +2924,14 @@
357 goto end_with_restore_list;
358 }
359
360- if (!(res= open_normal_and_derived_tables(thd, all_tables, 0)))
361+ res= open_normal_and_derived_tables(thd, all_tables, 0);
362+ if (res)
363+ {
364+ /* Got error or warning. Set res to 1 if error */
365+ if (!(res= thd->is_error()))
366+ my_ok(thd); // CREATE ... IF NOT EXISTS
367+ }
368+ else
369 {
370 /* The table already exists */
371 if (create_table->table || create_table->view)
372
373=== modified file 'Percona-Server/sql/sql_table.cc'
374--- Percona-Server/sql/sql_table.cc 2013-02-12 07:47:19 +0000
375+++ Percona-Server/sql/sql_table.cc 2013-02-20 09:38:26 +0000
376@@ -4949,7 +4949,8 @@
377 */
378 if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
379 {
380- result= TRUE;
381+ /* is_error() may be 0 if table existed and we generated a warning */
382+ result= thd->is_error();
383 goto end;
384 }
385
386@@ -5199,7 +5200,10 @@
387 properly isolated from all concurrent operations which matter.
388 */
389 if (open_tables(thd, &thd->lex->query_tables, &not_used, 0))
390+ {
391+ res= thd->is_error();
392 goto err;
393+ }
394 src_table->table->use_all_columns();
395
396 DEBUG_SYNC(thd, "create_table_like_after_open");

Subscribers

People subscribed via source and target branches