1 /*
2 Copyright (c) 2000, 2011, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software Foundation,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
16
17
18 /**
19 @file
20
21 Locking functions for mysql.
22
23 Because of the new concurrent inserts, we must first get external locks
24 before getting internal locks. If we do it in the other order, the status
25 information is not up to date when called from the lock handler.
26
27 GENERAL DESCRIPTION OF LOCKING
28
29 When not using LOCK TABLES:
30
31 - For each SQL statement mysql_lock_tables() is called for all involved
32 tables.
33 - mysql_lock_tables() will call
34 table_handler->external_lock(thd,locktype) for each table.
35 This is followed by a call to thr_multi_lock() for all tables.
36
37 - When statement is done, we call mysql_unlock_tables().
38 table_handler->external_lock(thd, F_UNLCK) followed by
39 thr_multi_unlock() for each table.
40
41 - Note that mysql_unlock_tables() may be called several times as
42 MySQL in some cases can free some tables earlier than others.
43
44 - The above is true both for normal and temporary tables.
45
46 - Temporary non transactional tables are never passed to thr_multi_lock()
47 and we never call external_lock(thd, F_UNLOCK) on these.
48
49 When using LOCK TABLES:
50
51 - LOCK TABLE will call mysql_lock_tables() for all tables.
52 mysql_lock_tables() will call
53 table_handler->external_lock(thd,locktype) for each table.
54 This is followed by a call to thr_multi_lock() for all tables.
55
56 - For each statement, we will call table_handler->start_stmt(THD)
57 to inform the table handler that we are using the table.
58
59 The tables used can only be tables used in LOCK TABLES or a
60 temporary table.
61
62 - When statement is done, we will call ha_commit_stmt(thd);
63
64 - When calling UNLOCK TABLES we call mysql_unlock_tables() for all
65 tables used in LOCK TABLES
66
67 If table_handler->external_lock(thd, locktype) fails, we call
68 table_handler->external_lock(thd, F_UNLCK) for each table that was locked,
69 excluding one that caused failure. That means handler must cleanup itself
70 in case external_lock() fails.
71 */
72
73 #include "mariadb.h"
74 #include "sql_priv.h"
75 #include "debug_sync.h"
76 #include "lock.h"
77 #include "sql_base.h" // close_tables_for_reopen
78 #include "sql_parse.h" // is_log_table_write_query
79 #include "sql_acl.h" // SUPER_ACL
80 #include <hash.h>
81 #include "wsrep_mysqld.h"
82
83 /**
84 @defgroup Locking Locking
85 @{
86 */
87
88 extern HASH open_cache;
89
90 static int lock_external(THD *thd, TABLE **table,uint count);
91 static int unlock_external(THD *thd, TABLE **table,uint count);
92
93
94 /* Map the return value of thr_lock to an error from errmsg.txt */
95 static int thr_lock_errno_to_mysql[]=
96 { 0, ER_LOCK_ABORTED, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
97
98 /**
99 Perform semantic checks for mysql_lock_tables.
100 @param thd The current thread
101 @param tables The tables to lock
102 @param count The number of tables to lock
103 @param flags Lock flags
104 @return 0 if all the check passed, non zero if a check failed.
105 */
106
107 static int
lock_tables_check(THD * thd,TABLE ** tables,uint count,uint flags)108 lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
109 {
110 uint system_count, i;
111 bool is_superuser, log_table_write_query;
112
113 DBUG_ENTER("lock_tables_check");
114
115 system_count= 0;
116 is_superuser= thd->security_ctx->master_access & SUPER_ACL;
117 log_table_write_query= (is_log_table_write_query(thd->lex->sql_command)
118 || ((flags & MYSQL_LOCK_LOG_TABLE) != 0));
119
120 for (i=0 ; i<count; i++)
121 {
122 TABLE *t= tables[i];
123
124 /* Protect against 'fake' partially initialized TABLE_SHARE */
125 DBUG_ASSERT(t->s->table_category != TABLE_UNKNOWN_CATEGORY);
126
127 /*
128 Table I/O to performance schema tables is performed
129 only internally by the server implementation.
130 When a user is requesting a lock, the following
131 constraints are enforced:
132 */
133 if (t->s->require_write_privileges() &&
134 ! log_table_write_query)
135 {
136 /*
137 A user should not be able to prevent writes,
138 or hold any type of lock in a session,
139 since this would be a DOS attack.
140 */
141 if ((t->reginfo.lock_type >= TL_READ_NO_INSERT)
142 || (thd->lex->sql_command == SQLCOM_LOCK_TABLES))
143 {
144 my_error(ER_CANT_LOCK_LOG_TABLE, MYF(0));
145 DBUG_RETURN(1);
146 }
147 }
148
149 if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)
150 {
151 if (t->s->table_category == TABLE_CATEGORY_SYSTEM)
152 system_count++;
153
154 if (t->db_stat & HA_READ_ONLY)
155 {
156 my_error(ER_OPEN_AS_READONLY, MYF(0), t->alias.c_ptr_safe());
157 DBUG_RETURN(1);
158 }
159 }
160
161 /*
162 If we are going to lock a non-temporary table we must own metadata
163 lock of appropriate type on it (I.e. for table to be locked for
164 write we must own metadata lock of MDL_SHARED_WRITE or stronger
165 type. For table to be locked for read we must own metadata lock
166 of MDL_SHARED_READ or stronger type).
167 */
168 DBUG_ASSERT(t->s->tmp_table ||
169 thd->mdl_context.is_lock_owner(MDL_key::TABLE,
170 t->s->db.str, t->s->table_name.str,
171 t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE ?
172 MDL_SHARED_WRITE : MDL_SHARED_READ));
173
174 /*
175 Prevent modifications to base tables if READ_ONLY is activated.
176 In any case, read only does not apply to temporary tables.
177 */
178 if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table)
179 {
180 if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
181 !is_superuser && opt_readonly && !thd->slave_thread)
182 {
183 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
184 DBUG_RETURN(1);
185 }
186 }
187 }
188
189 /*
190 Locking of system tables is restricted:
191 locking a mix of system and non-system tables in the same lock
192 is prohibited, to prevent contention.
193 */
194 if ((system_count > 0) && (system_count < count))
195 {
196 my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
197 DBUG_RETURN(1);
198 }
199
200 DBUG_RETURN(0);
201 }
202
203 /**
204 Reset lock type in lock data
205
206 @param mysql_lock Lock structures to reset.
207 @param unlock If set, then set lock type to TL_UNLOCK,
208 otherwise set to original lock type from
209 get_store_lock().
210
211 @note After a locking error we want to quit the locking of the table(s).
212 The test case in the bug report for Bug #18544 has the following
213 cases: 1. Locking error in lock_external() due to InnoDB timeout.
214 2. Locking error in get_lock_data() due to missing write permission.
215 3. Locking error in wait_if_global_read_lock() due to lock conflict.
216
217 @note In all these cases we have already set the lock type into the lock
218 data of the open table(s). If the table(s) are in the open table
219 cache, they could be reused with the non-zero lock type set. This
220 could lead to ignoring a different lock type with the next lock.
221
222 @note Clear the lock type of all lock data. This ensures that the next
223 lock request will set its lock type properly.
224 */
225
226
reset_lock_data(MYSQL_LOCK * sql_lock,bool unlock)227 void reset_lock_data(MYSQL_LOCK *sql_lock, bool unlock)
228 {
229 THR_LOCK_DATA **ldata, **ldata_end;
230 DBUG_ENTER("reset_lock_data");
231
232 /* Clear the lock type of all lock data to avoid reusage. */
233 for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
234 ldata < ldata_end;
235 ldata++)
236 (*ldata)->type= unlock ? TL_UNLOCK : (*ldata)->org_type;
237 DBUG_VOID_RETURN;
238 }
239
240
241 /**
242 Scan array of tables for access types; update transaction tracker
243 accordingly.
244
245 @param thd The current thread.
246 @param tables An array of pointers to the tables to lock.
247 @param count The number of tables to lock.
248 */
249
250 #ifndef EMBEDDED_LIBRARY
track_table_access(THD * thd,TABLE ** tables,size_t count)251 static void track_table_access(THD *thd, TABLE **tables, size_t count)
252 {
253 if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
254 {
255 while (count--)
256 {
257 if (TABLE *t= tables[count])
258 thd->session_tracker.transaction_info.add_trx_state(thd,
259 t->reginfo.lock_type, t->file->has_transaction_manager());
260 }
261 }
262 }
263 #else
264 #define track_table_access(A,B,C)
265 #endif //EMBEDDED_LIBRARY
266
267
268
269 /**
270 Lock tables.
271
272 @param thd The current thread.
273 @param tables An array of pointers to the tables to lock.
274 @param count The number of tables to lock.
275 @param flags Options:
276 MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
277 MYSQL_LOCK_IGNORE_TIMEOUT Use maximum timeout value.
278
279 @retval A lock structure pointer on success.
280 @retval NULL if an error or if wait on a lock was killed.
281 */
282
mysql_lock_tables(THD * thd,TABLE ** tables,uint count,uint flags)283 MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
284 {
285 MYSQL_LOCK *sql_lock;
286 uint gld_flags= GET_LOCK_STORE_LOCKS;
287 DBUG_ENTER("mysql_lock_tables(tables)");
288
289 if (lock_tables_check(thd, tables, count, flags))
290 DBUG_RETURN(NULL);
291
292 if (!(thd->variables.option_bits & OPTION_TABLE_LOCK) &&
293 !(flags & MYSQL_LOCK_USE_MALLOC))
294 gld_flags|= GET_LOCK_ON_THD;
295
296 if (! (sql_lock= get_lock_data(thd, tables, count, gld_flags)))
297 DBUG_RETURN(NULL);
298
299 if (mysql_lock_tables(thd, sql_lock, flags))
300 {
301 /* Clear the lock type of all lock data to avoid reusage. */
302 reset_lock_data(sql_lock, 1);
303 if (!(gld_flags & GET_LOCK_ON_THD))
304 my_free(sql_lock);
305 sql_lock= 0;
306 }
307
308 track_table_access(thd, tables, count);
309
310 DBUG_RETURN(sql_lock);
311 }
312
313 /**
314 Lock tables based on a MYSQL_LOCK structure.
315
316 mysql_lock_tables()
317
318 @param thd The current thread.
319 @param sql_lock Tables that should be locked
320 @param flags See mysql_lock_tables() above
321
322 @return 0 ok
323 @return 1 error
324 */
325
mysql_lock_tables(THD * thd,MYSQL_LOCK * sql_lock,uint flags)326 bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
327 {
328 int rc= 1;
329 ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ?
330 LONG_TIMEOUT : thd->variables.lock_wait_timeout;
331 PSI_stage_info org_stage;
332 DBUG_ENTER("mysql_lock_tables(sql_lock)");
333
334 thd->backup_stage(&org_stage);
335 THD_STAGE_INFO(thd, stage_system_lock);
336 if (sql_lock->table_count && lock_external(thd, sql_lock->table,
337 sql_lock->table_count))
338 goto end;
339
340 THD_STAGE_INFO(thd, stage_table_lock);
341
342 /* Copy the lock data array. thr_multi_lock() reorders its contents. */
343 memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
344 sql_lock->lock_count * sizeof(*sql_lock->locks));
345
346 /* Lock on the copied half of the lock data array. */
347 rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
348 sql_lock->lock_count,
349 sql_lock->lock_count,
350 &thd->lock_info, timeout)];
351 if (rc && sql_lock->table_count)
352 (void) unlock_external(thd, sql_lock->table, sql_lock->table_count);
353
354 end:
355 THD_STAGE_INFO(thd, org_stage);
356
357 if (thd->killed)
358 {
359 thd->send_kill_message();
360 if (!rc)
361 {
362 mysql_unlock_tables(thd, sql_lock, 0);
363 THD_STAGE_INFO(thd, stage_after_table_lock);
364 }
365 rc= 1;
366 }
367 else if (rc > 1)
368 my_error(rc, MYF(0));
369
370 thd->set_time_after_lock();
371 DBUG_RETURN(rc);
372 }
373
374
lock_external(THD * thd,TABLE ** tables,uint count)375 static int lock_external(THD *thd, TABLE **tables, uint count)
376 {
377 uint i;
378 int lock_type,error;
379 DBUG_ENTER("lock_external");
380
381 DBUG_PRINT("info", ("count %d", count));
382 for (i=1 ; i <= count ; i++, tables++)
383 {
384 DBUG_ASSERT((*tables)->reginfo.lock_type >= TL_READ);
385 lock_type=F_WRLCK; /* Lock exclusive */
386 if ((*tables)->db_stat & HA_READ_ONLY ||
387 ((*tables)->reginfo.lock_type >= TL_READ &&
388 (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
389 lock_type=F_RDLCK;
390
391 if (unlikely((error=(*tables)->file->ha_external_lock(thd,lock_type))))
392 {
393 (*tables)->file->print_error(error, MYF(0));
394 while (--i)
395 {
396 tables--;
397 (*tables)->file->ha_external_lock(thd, F_UNLCK);
398 (*tables)->current_lock=F_UNLCK;
399 }
400 DBUG_RETURN(error);
401 }
402 else
403 {
404 (*tables)->current_lock= lock_type;
405 }
406 }
407 DBUG_RETURN(0);
408 }
409
410
mysql_unlock_tables(THD * thd,MYSQL_LOCK * sql_lock)411 void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
412 {
413 mysql_unlock_tables(thd, sql_lock,
414 (thd->variables.option_bits & OPTION_TABLE_LOCK) ||
415 !(sql_lock->flags & GET_LOCK_ON_THD));
416 }
417
418
mysql_unlock_tables(THD * thd,MYSQL_LOCK * sql_lock,bool free_lock)419 void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
420 {
421 bool errors= thd->is_error();
422 PSI_stage_info org_stage;
423 DBUG_ENTER("mysql_unlock_tables");
424
425 thd->backup_stage(&org_stage);
426 THD_STAGE_INFO(thd, stage_unlocking_tables);
427
428 if (sql_lock->table_count)
429 unlock_external(thd, sql_lock->table, sql_lock->table_count);
430 if (sql_lock->lock_count)
431 thr_multi_unlock(sql_lock->locks, sql_lock->lock_count, 0);
432 if (free_lock)
433 {
434 DBUG_ASSERT(!(sql_lock->flags & GET_LOCK_ON_THD));
435 my_free(sql_lock);
436 }
437 if (likely(!errors))
438 thd->clear_error();
439 THD_STAGE_INFO(thd, org_stage);
440 DBUG_VOID_RETURN;
441 }
442
443 /**
444 Unlock some of the tables locked by mysql_lock_tables.
445
446 This will work even if get_lock_data fails (next unlock will free all)
447 */
448
mysql_unlock_some_tables(THD * thd,TABLE ** table,uint count,uint flag)449 void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag)
450 {
451 MYSQL_LOCK *sql_lock=
452 get_lock_data(thd, table, count, GET_LOCK_UNLOCK | GET_LOCK_ON_THD | flag);
453 if (sql_lock)
454 mysql_unlock_tables(thd, sql_lock, 0);
455 }
456
457
458 /**
459 unlock all tables locked for read.
460 */
461
mysql_unlock_read_tables(THD * thd,MYSQL_LOCK * sql_lock)462 void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
463 {
464 uint i,found;
465 DBUG_ENTER("mysql_unlock_read_tables");
466
467 /* Call external lock for all tables to be unlocked */
468
469 /* Move all write locked tables first */
470 TABLE **table=sql_lock->table;
471 for (i=found=0 ; i < sql_lock->table_count ; i++)
472 {
473 DBUG_ASSERT(sql_lock->table[i]->lock_position == i);
474 if ((uint) sql_lock->table[i]->reginfo.lock_type > TL_WRITE_ALLOW_WRITE)
475 {
476 swap_variables(TABLE *, *table, sql_lock->table[i]);
477 table++;
478 found++;
479 }
480 }
481 /* Unlock all read locked tables */
482 if (i != found)
483 {
484 (void) unlock_external(thd,table,i-found);
485 sql_lock->table_count=found;
486 }
487
488 /* Call thr_unlock() for all tables to be unlocked */
489
490 /* Move all write locks first */
491 THR_LOCK_DATA **lock=sql_lock->locks;
492 for (i=found=0 ; i < sql_lock->lock_count ; i++)
493 {
494 if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_WRITE)
495 {
496 swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
497 lock++;
498 found++;
499 }
500 }
501 /* unlock the read locked tables */
502 if (i != found)
503 {
504 thr_multi_unlock(lock, i-found, 0);
505 sql_lock->lock_count= found;
506 }
507
508 /* Fix the lock positions in TABLE */
509 table= sql_lock->table;
510 found= 0;
511 for (i= 0; i < sql_lock->table_count; i++)
512 {
513 TABLE *tbl= *table;
514 tbl->lock_position= (uint) (table - sql_lock->table);
515 tbl->lock_data_start= found;
516 found+= tbl->lock_count;
517 table++;
518 }
519 DBUG_VOID_RETURN;
520 }
521
522
523 /**
524 Try to find the table in the list of locked tables.
525 In case of success, unlock the table and remove it from this list.
526 If a table has more than one lock instance, removes them all.
527
528 @param thd thread context
529 @param locked list of locked tables
530 @param table the table to unlock
531 */
532
mysql_lock_remove(THD * thd,MYSQL_LOCK * locked,TABLE * table)533 void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
534 {
535 if (locked)
536 {
537 uint i;
538 for (i=0; i < locked->table_count; i++)
539 {
540 if (locked->table[i] == table)
541 {
542 uint j, removed_locks, old_tables;
543 TABLE *tbl;
544 uint lock_data_end;
545
546 DBUG_ASSERT(table->lock_position == i);
547
548 /* Unlock the table. */
549 mysql_unlock_some_tables(thd, &table, /* table count */ 1, 0);
550
551 /* Decrement table_count in advance, making below expressions easier */
552 old_tables= --locked->table_count;
553
554 /* The table has 'removed_locks' lock data elements in locked->locks */
555 removed_locks= table->lock_count;
556
557 /* Move down all table pointers above 'i'. */
558 bmove((char*) (locked->table+i),
559 (char*) (locked->table+i+1),
560 (old_tables - i) * sizeof(TABLE*));
561
562 lock_data_end= table->lock_data_start + table->lock_count;
563 /* Move down all lock data pointers above 'table->lock_data_end-1' */
564 bmove((char*) (locked->locks + table->lock_data_start),
565 (char*) (locked->locks + lock_data_end),
566 (locked->lock_count - lock_data_end) *
567 sizeof(THR_LOCK_DATA*));
568
569 /*
570 Fix moved table elements.
571 lock_position is the index in the 'locked->table' array,
572 it must be fixed by one.
573 table->lock_data_start is pointer to the lock data for this table
574 in the 'locked->locks' array, they must be fixed by 'removed_locks',
575 the lock data count of the removed table.
576 */
577 for (j= i ; j < old_tables; j++)
578 {
579 tbl= locked->table[j];
580 tbl->lock_position--;
581 DBUG_ASSERT(tbl->lock_position == j);
582 tbl->lock_data_start-= removed_locks;
583 }
584
585 /* Finally adjust lock_count. */
586 locked->lock_count-= removed_locks;
587 break;
588 }
589 }
590 }
591 }
592
593
594 /**
595 Abort one thread / table combination.
596
597 @param thd Thread handler
598 @param table Table that should be removed from lock queue
599
600 @retval
601 0 Table was not locked by another thread
602 @retval
603 1 Table was locked by at least one other thread
604 */
605
mysql_lock_abort_for_thread(THD * thd,TABLE * table)606 bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
607 {
608 MYSQL_LOCK *locked;
609 bool result= FALSE;
610 DBUG_ENTER("mysql_lock_abort_for_thread");
611
612 if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK | GET_LOCK_ON_THD)))
613 {
614 for (uint i=0; i < locked->lock_count; i++)
615 {
616 if (thr_abort_locks_for_thread(locked->locks[i]->lock,
617 table->in_use->thread_id))
618 result= TRUE;
619 }
620 }
621 DBUG_RETURN(result);
622 }
623
624
625 /**
626 Merge two thr_lock:s
627 mysql_lock_merge()
628
629 @param a Original locks
630 @param b New locks
631
632 @retval New lock structure that contains a and b
633
634 @note
635 a and b are freed with my_free()
636 */
637
mysql_lock_merge(MYSQL_LOCK * a,MYSQL_LOCK * b)638 MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
639 {
640 MYSQL_LOCK *sql_lock;
641 TABLE **table, **end_table;
642 DBUG_ENTER("mysql_lock_merge");
643 DBUG_PRINT("enter", ("a->lock_count: %u b->lock_count: %u",
644 a->lock_count, b->lock_count));
645
646 if (!(sql_lock= (MYSQL_LOCK*)
647 my_malloc(sizeof(*sql_lock)+
648 sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) +
649 sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
650 DBUG_RETURN(0); // Fatal error
651 sql_lock->lock_count=a->lock_count+b->lock_count;
652 sql_lock->table_count=a->table_count+b->table_count;
653 sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
654 sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count*2);
655 sql_lock->flags= 0;
656 memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
657 memcpy(sql_lock->locks+a->lock_count,b->locks,
658 b->lock_count*sizeof(*b->locks));
659 memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
660 memcpy(sql_lock->table+a->table_count,b->table,
661 b->table_count*sizeof(*b->table));
662
663 /*
664 Now adjust lock_position and lock_data_start for all objects that was
665 moved in 'b' (as there is now all objects in 'a' before these).
666 */
667 for (table= sql_lock->table + a->table_count,
668 end_table= table + b->table_count;
669 table < end_table;
670 table++)
671 {
672 (*table)->lock_position+= a->table_count;
673 (*table)->lock_data_start+= a->lock_count;
674 }
675
676 /*
677 Ensure that locks of the same tables share same data structures if we
678 reopen a table that is already open. This can happen for example with
679 MERGE tables.
680 */
681
682 /* Copy the lock data array. thr_merge_lock() reorders its content */
683 memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
684 sql_lock->lock_count * sizeof(*sql_lock->locks));
685 thr_merge_locks(sql_lock->locks + sql_lock->lock_count,
686 a->lock_count, b->lock_count);
687
688 /* Delete old, not needed locks */
689 my_free(a);
690 my_free(b);
691 DBUG_RETURN(sql_lock);
692 }
693
694
695 /** Unlock a set of external. */
696
unlock_external(THD * thd,TABLE ** table,uint count)697 static int unlock_external(THD *thd, TABLE **table,uint count)
698 {
699 int error,error_code;
700 DBUG_ENTER("unlock_external");
701
702 error_code=0;
703 do
704 {
705 if ((*table)->current_lock != F_UNLCK)
706 {
707 (*table)->current_lock = F_UNLCK;
708 if (unlikely((error=(*table)->file->ha_external_lock(thd, F_UNLCK))))
709 {
710 error_code= error;
711 (*table)->file->print_error(error, MYF(0));
712 }
713 }
714 table++;
715 } while (--count);
716 DBUG_RETURN(error_code);
717 }
718
719
720 /**
721 Get lock structures from table structs and initialize locks.
722
723 @param thd Thread handler
724 @param table_ptr Pointer to tables that should be locks
725 @param flags One of:
726 - GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
727 - GET_LOCK_STORE_LOCKS : Store lock info in TABLE
728 - GET_LOCK_SKIP_SEQUENCES : Ignore sequences (for temporary unlock)
729 - GET_LOCK_ON_THD : Store lock in thd->mem_root
730
731 Temporary tables are not locked (as these are single user), except for
732 TRANSACTIONAL_TMP_TABLES as locking is needed to handle transactions.
733 */
734
get_lock_data(THD * thd,TABLE ** table_ptr,uint count,uint flags)735 MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
736 {
737 uint i,lock_count,table_count;
738 MYSQL_LOCK *sql_lock;
739 THR_LOCK_DATA **locks, **locks_buf;
740 TABLE **to, **table_buf;
741 DBUG_ENTER("get_lock_data");
742
743 DBUG_PRINT("info", ("count %d", count));
744
745 for (i=lock_count=table_count=0 ; i < count ; i++)
746 {
747 TABLE *t= table_ptr[i];
748
749 if ((likely(!t->s->tmp_table) ||
750 (t->s->tmp_table == TRANSACTIONAL_TMP_TABLE)) &&
751 (!(flags & GET_LOCK_SKIP_SEQUENCES) || t->s->sequence == 0))
752 {
753 lock_count+= t->file->lock_count();
754 table_count++;
755 }
756 }
757
758 /*
759 Allocating twice the number of pointers for lock data for use in
760 thr_multi_lock(). This function reorders the lock data, but cannot
761 update the table values. So the second part of the array is copied
762 from the first part immediately before calling thr_multi_lock().
763 */
764 size_t amount= sizeof(*sql_lock) +
765 sizeof(THR_LOCK_DATA*) * lock_count * 2 +
766 sizeof(table_ptr) * table_count;
767 if (!(sql_lock= (MYSQL_LOCK*) (flags & GET_LOCK_ON_THD ?
768 thd->alloc(amount) :
769 my_malloc(amount, MYF(0)))))
770 DBUG_RETURN(0);
771 locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
772 to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2);
773 sql_lock->table_count= table_count;
774 sql_lock->flags= flags;
775
776 for (i=0 ; i < count ; i++)
777 {
778 TABLE *table= table_ptr[i];
779 enum thr_lock_type lock_type;
780 THR_LOCK_DATA **locks_start;
781
782 if (!((likely(!table->s->tmp_table) ||
783 (table->s->tmp_table == TRANSACTIONAL_TMP_TABLE)) &&
784 (!(flags & GET_LOCK_SKIP_SEQUENCES) || table->s->sequence == 0)))
785 continue;
786 lock_type= table->reginfo.lock_type;
787 DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
788 locks_start= locks;
789 locks= table->file->store_lock(thd, locks,
790 (flags & GET_LOCK_ACTION_MASK) == GET_LOCK_UNLOCK ? TL_IGNORE :
791 lock_type);
792 if ((flags & GET_LOCK_ACTION_MASK) == GET_LOCK_STORE_LOCKS)
793 {
794 table->lock_position= (uint) (to - table_buf);
795 table->lock_data_start= (uint) (locks_start - locks_buf);
796 table->lock_count= (uint) (locks - locks_start);
797 }
798 *to++= table;
799 if (locks)
800 {
801 for ( ; locks_start != locks ; locks_start++)
802 {
803 (*locks_start)->debug_print_param= (void *) table;
804 (*locks_start)->m_psi= table->file->m_psi;
805 (*locks_start)->lock->name= table->alias.c_ptr();
806 (*locks_start)->org_type= (*locks_start)->type;
807 }
808 }
809 }
810 /*
811 We do not use 'lock_count', because there are cases where store_lock()
812 returns less locks than lock_count() claimed. This can happen when
813 a FLUSH TABLES tries to abort locks from a MERGE table of another
814 thread. When that thread has just opened the table, but not yet
815 attached its children, it cannot return the locks. lock_count()
816 always returns the number of locks that an attached table has.
817 This is done to avoid the reverse situation: If lock_count() would
818 return 0 for a non-attached MERGE table, and that table becomes
819 attached between the calls to lock_count() and store_lock(), then
820 we would have allocated too little memory for the lock data. Now
821 we may allocate too much, but better safe than memory overrun.
822 And in the FLUSH case, the memory is released quickly anyway.
823 */
824 sql_lock->lock_count= (uint)(locks - locks_buf);
825 DBUG_ASSERT(sql_lock->lock_count <= lock_count);
826 DBUG_PRINT("info", ("sql_lock->table_count %d sql_lock->lock_count %d",
827 sql_lock->table_count, sql_lock->lock_count));
828 DBUG_RETURN(sql_lock);
829 }
830
831
832 /**
833 Obtain an exclusive metadata lock on a schema name.
834
835 @param thd Thread handle.
836 @param db The database name.
837
838 To avoid deadlocks, we do not try to obtain exclusive metadata
839 locks in LOCK TABLES mode, since in this mode there may be
840 other metadata locks already taken by the current connection,
841 and we must not wait for MDL locks while holding locks.
842
843 @retval FALSE Success.
844 @retval TRUE Failure: we're in LOCK TABLES mode, or out of memory,
845 or this connection was killed.
846 */
847
lock_schema_name(THD * thd,const char * db)848 bool lock_schema_name(THD *thd, const char *db)
849 {
850 MDL_request_list mdl_requests;
851 MDL_request global_request;
852 MDL_request mdl_request;
853
854 if (thd->locked_tables_mode)
855 {
856 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
857 ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
858 return TRUE;
859 }
860
861 if (thd->global_read_lock.can_acquire_protection())
862 return TRUE;
863 global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
864 MDL_STATEMENT);
865 mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE, MDL_TRANSACTION);
866
867 mdl_requests.push_front(&mdl_request);
868 mdl_requests.push_front(&global_request);
869
870 if (thd->mdl_context.acquire_locks(&mdl_requests,
871 thd->variables.lock_wait_timeout))
872 return TRUE;
873
874 DEBUG_SYNC(thd, "after_wait_locked_schema_name");
875 return FALSE;
876 }
877
878
879 /**
880 Obtain an exclusive metadata lock on an object name.
881
882 @param thd Thread handle.
883 @param mdl_type Object type (currently functions, procedures
884 and events can be name-locked).
885 @param db The schema the object belongs to.
886 @param name Object name in the schema.
887
888 This function assumes that no metadata locks were acquired
889 before calling it. It is enforced by asserts in MDL_context::acquire_locks().
890 To avoid deadlocks, we do not try to obtain exclusive metadata
891 locks in LOCK TABLES mode, since in this mode there may be
892 other metadata locks already taken by the current connection,
893 and we must not wait for MDL locks while holding locks.
894
895 @retval FALSE Success.
896 @retval TRUE Failure: we're in LOCK TABLES mode, or out of memory,
897 or this connection was killed.
898 */
899
lock_object_name(THD * thd,MDL_key::enum_mdl_namespace mdl_type,const char * db,const char * name)900 bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
901 const char *db, const char *name)
902 {
903 MDL_request_list mdl_requests;
904 MDL_request global_request;
905 MDL_request schema_request;
906 MDL_request mdl_request;
907
908 DBUG_SLOW_ASSERT(ok_for_lower_case_names(db));
909
910 if (thd->locked_tables_mode)
911 {
912 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
913 ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
914 return TRUE;
915 }
916
917 DBUG_ASSERT(name);
918 DEBUG_SYNC(thd, "before_wait_locked_pname");
919
920 if (thd->global_read_lock.can_acquire_protection())
921 return TRUE;
922 global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
923 MDL_STATEMENT);
924 schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE,
925 MDL_TRANSACTION);
926 mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE, MDL_TRANSACTION);
927
928 mdl_requests.push_front(&mdl_request);
929 mdl_requests.push_front(&schema_request);
930 mdl_requests.push_front(&global_request);
931
932 if (thd->mdl_context.acquire_locks(&mdl_requests,
933 thd->variables.lock_wait_timeout))
934 return TRUE;
935
936 DEBUG_SYNC(thd, "after_wait_locked_pname");
937 return FALSE;
938 }
939
940
941 /****************************************************************************
942 Handling of global read locks
943
944 Global read lock is implemented using metadata lock infrastructure.
945
946 Taking the global read lock is TWO steps (2nd step is optional; without
947 it, COMMIT of existing transactions will be allowed):
948 lock_global_read_lock() THEN make_global_read_lock_block_commit().
949
950 How blocking of threads by global read lock is achieved: that's
951 semi-automatic. We assume that any statement which should be blocked
952 by global read lock will either open and acquires write-lock on tables
953 or acquires metadata locks on objects it is going to modify. For any
954 such statement global IX metadata lock is automatically acquired for
955 its duration (in case of LOCK TABLES until end of LOCK TABLES mode).
956 And lock_global_read_lock() simply acquires global S metadata lock
957 and thus prohibits execution of statements which modify data (unless
958 they modify only temporary tables). If deadlock happens it is detected
959 by MDL subsystem and resolved in the standard fashion (by backing-off
960 metadata locks acquired so far and restarting open tables process
961 if possible).
962
963 Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
964 to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
965 log.
966
967 Why getting the global read lock is two steps and not one. Because FLUSH
968 TABLES WITH READ LOCK needs to insert one other step between the two:
969 flushing tables. So the order is
970 1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
971 all new updates)
972 2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
973 currently opened and being updated to close (so it's possible that there is
974 a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
975 READ LOCK is, too).
976 3) make_global_read_lock_block_commit().
977 If we have merged 1) and 3) into 1), we would have had this deadlock:
978 imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
979 table t.
980 thd1: SELECT * FROM t FOR UPDATE;
981 thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
982 thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
983 table instance of thd2
984 thd1: COMMIT; # blocked by thd3.
985 thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
986
987 Note that we need to support that one thread does
988 FLUSH TABLES WITH READ LOCK; and then COMMIT;
989 (that's what innobackup does, for some good reason).
990 So in this exceptional case the COMMIT should not be blocked by the FLUSH
991 TABLES WITH READ LOCK.
992
993 ****************************************************************************/
994
995 /**
996 Take global read lock, wait if there is protection against lock.
997
998 If the global read lock is already taken by this thread, then nothing is done.
999
1000 See also "Handling of global read locks" above.
1001
1002 @param thd Reference to thread.
1003
1004 @retval False Success, global read lock set, commits are NOT blocked.
1005 @retval True Failure, thread was killed.
1006 */
1007
lock_global_read_lock(THD * thd)1008 bool Global_read_lock::lock_global_read_lock(THD *thd)
1009 {
1010 DBUG_ENTER("lock_global_read_lock");
1011
1012 if (!m_state)
1013 {
1014 MDL_request mdl_request;
1015
1016 DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
1017 MDL_SHARED));
1018 mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED, MDL_EXPLICIT);
1019
1020 if (thd->mdl_context.acquire_lock(&mdl_request,
1021 thd->variables.lock_wait_timeout))
1022 DBUG_RETURN(1);
1023
1024 m_mdl_global_shared_lock= mdl_request.ticket;
1025 m_state= GRL_ACQUIRED;
1026 }
1027 /*
1028 We DON'T set global_read_lock_blocks_commit now, it will be set after
1029 tables are flushed (as the present function serves for FLUSH TABLES WITH
1030 READ LOCK only). Doing things in this order is necessary to avoid
1031 deadlocks (we must allow COMMIT until all tables are closed; we should not
1032 forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
1033 UPDATE and one does FLUSH TABLES WITH READ LOCK).
1034 */
1035 DBUG_RETURN(0);
1036 }
1037
1038
1039 /**
1040 Unlock global read lock.
1041
1042 Commits may or may not be blocked when this function is called.
1043
1044 See also "Handling of global read locks" above.
1045
1046 @param thd Reference to thread.
1047 */
1048
unlock_global_read_lock(THD * thd)1049 void Global_read_lock::unlock_global_read_lock(THD *thd)
1050 {
1051 DBUG_ENTER("unlock_global_read_lock");
1052
1053 DBUG_ASSERT(m_mdl_global_shared_lock && m_state);
1054
1055 if (thd->global_disable_checkpoint)
1056 {
1057 thd->global_disable_checkpoint= 0;
1058 if (!--global_disable_checkpoint)
1059 {
1060 ha_checkpoint_state(0); // Enable checkpoints
1061 }
1062 }
1063
1064 if (m_mdl_blocks_commits_lock)
1065 {
1066 thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
1067 m_mdl_blocks_commits_lock= NULL;
1068 #ifdef WITH_WSREP
1069 if (WSREP(thd) || wsrep_node_is_donor())
1070 {
1071 wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
1072 wsrep->resume(wsrep);
1073 /* resync here only if we did implicit desync earlier */
1074 if (!wsrep_desync && wsrep_node_is_synced())
1075 {
1076 int ret = wsrep->resync(wsrep);
1077 if (ret != WSREP_OK)
1078 {
1079 WSREP_WARN("resync failed %d for FTWRL: db: %s, query: %s",
1080 ret, thd->get_db(), thd->query());
1081 DBUG_VOID_RETURN;
1082 }
1083 }
1084 }
1085 #endif /* WITH_WSREP */
1086 }
1087 thd->mdl_context.release_lock(m_mdl_global_shared_lock);
1088 m_mdl_global_shared_lock= NULL;
1089 m_state= GRL_NONE;
1090
1091 DBUG_VOID_RETURN;
1092 }
1093
1094
1095 /**
1096 Make global read lock also block commits.
1097
1098 The scenario is:
1099 - This thread has the global read lock.
1100 - Global read lock blocking of commits is not set.
1101
1102 See also "Handling of global read locks" above.
1103
1104 @param thd Reference to thread.
1105
1106 @retval False Success, global read lock set, commits are blocked.
1107 @retval True Failure, thread was killed.
1108 */
1109
make_global_read_lock_block_commit(THD * thd)1110 bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
1111 {
1112 MDL_request mdl_request;
1113 DBUG_ENTER("make_global_read_lock_block_commit");
1114 /*
1115 If we didn't succeed lock_global_read_lock(), or if we already succeeded
1116 make_global_read_lock_block_commit(), do nothing.
1117 */
1118
1119 if (m_state != GRL_ACQUIRED)
1120 DBUG_RETURN(0);
1121
1122 #ifdef WITH_WSREP
1123 if (WSREP(thd) && m_mdl_blocks_commits_lock)
1124 {
1125 WSREP_DEBUG("GRL was in block commit mode when entering "
1126 "make_global_read_lock_block_commit");
1127 DBUG_RETURN(FALSE);
1128 }
1129 #endif /* WITH_WSREP */
1130
1131 mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT);
1132
1133 if (thd->mdl_context.acquire_lock(&mdl_request,
1134 thd->variables.lock_wait_timeout))
1135 DBUG_RETURN(TRUE);
1136
1137 m_mdl_blocks_commits_lock= mdl_request.ticket;
1138 m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
1139
1140 #ifdef WITH_WSREP
1141 /* Native threads should bail out before wsrep oprations to follow.
1142 Donor servicing thread is an exception, it should pause provider but not desync,
1143 as it is already desynced in donor state
1144 */
1145 if (!WSREP(thd) && !wsrep_node_is_donor())
1146 {
1147 DBUG_RETURN(FALSE);
1148 }
1149
1150 /* if already desynced or donor, avoid double desyncing
1151 if not in PC and synced, desyncing is not possible either
1152 */
1153 if (wsrep_desync || !wsrep_node_is_synced())
1154 {
1155 WSREP_DEBUG("desync set upfont, skipping implicit desync for FTWRL: %d",
1156 wsrep_desync);
1157 }
1158 else
1159 {
1160 int rcode;
1161 WSREP_DEBUG("running implicit desync for node");
1162 rcode = wsrep->desync(wsrep);
1163 if (rcode != WSREP_OK)
1164 {
1165 WSREP_WARN("FTWRL desync failed %d for schema: %s, query: %s",
1166 rcode, thd->get_db(), thd->query());
1167 my_message(ER_LOCK_DEADLOCK, "wsrep desync failed for FTWRL", MYF(0));
1168 DBUG_RETURN(TRUE);
1169 }
1170 }
1171
1172 long long ret = wsrep->pause(wsrep);
1173 if (ret >= 0)
1174 {
1175 wsrep_locked_seqno= ret;
1176 }
1177 else if (ret != -ENOSYS) /* -ENOSYS - no provider */
1178 {
1179 long long ret = wsrep->pause(wsrep);
1180 if (ret >= 0)
1181 {
1182 wsrep_locked_seqno= ret;
1183 }
1184 else if (ret != -ENOSYS) /* -ENOSYS - no provider */
1185 {
1186 WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret));
1187
1188 DBUG_ASSERT(m_mdl_blocks_commits_lock == NULL);
1189 wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
1190 my_error(ER_LOCK_DEADLOCK, MYF(0));
1191 DBUG_RETURN(TRUE);
1192 }
1193 }
1194 #endif /* WITH_WSREP */
1195 DBUG_RETURN(FALSE);
1196 }
1197
1198
1199 /**
1200 Set explicit duration for metadata locks which are used to implement GRL.
1201
1202 @param thd Reference to thread.
1203 */
1204
set_explicit_lock_duration(THD * thd)1205 void Global_read_lock::set_explicit_lock_duration(THD *thd)
1206 {
1207 if (m_mdl_global_shared_lock)
1208 thd->mdl_context.set_lock_duration(m_mdl_global_shared_lock, MDL_EXPLICIT);
1209 if (m_mdl_blocks_commits_lock)
1210 thd->mdl_context.set_lock_duration(m_mdl_blocks_commits_lock, MDL_EXPLICIT);
1211 }
1212
1213 /**
1214 @} (end of group Locking)
1215 */
1216