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, Suite 500, 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
88extern HASH open_cache;
89
90static int lock_external(THD *thd, TABLE **table,uint count);
91static 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 */
95static 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
107static int
108lock_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
227void 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
251static 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 Transaction_state_tracker *tst= (Transaction_state_tracker *)
256 thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER);
257
258 while (count--)
259 {
260 TABLE *t= tables[count];
261
262 if (t)
263 tst->add_trx_state(thd, t->reginfo.lock_type,
264 t->file->has_transaction_manager());
265 }
266 }
267}
268#else
269#define track_table_access(A,B,C)
270#endif //EMBEDDED_LIBRARY
271
272
273
274/**
275 Lock tables.
276
277 @param thd The current thread.
278 @param tables An array of pointers to the tables to lock.
279 @param count The number of tables to lock.
280 @param flags Options:
281 MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
282 MYSQL_LOCK_IGNORE_TIMEOUT Use maximum timeout value.
283
284 @retval A lock structure pointer on success.
285 @retval NULL if an error or if wait on a lock was killed.
286*/
287
288MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
289{
290 MYSQL_LOCK *sql_lock;
291 uint gld_flags= GET_LOCK_STORE_LOCKS;
292 DBUG_ENTER("mysql_lock_tables(tables)");
293
294 if (lock_tables_check(thd, tables, count, flags))
295 DBUG_RETURN(NULL);
296
297 if (!(thd->variables.option_bits & OPTION_TABLE_LOCK) &&
298 !(flags & MYSQL_LOCK_USE_MALLOC))
299 gld_flags|= GET_LOCK_ON_THD;
300
301 if (! (sql_lock= get_lock_data(thd, tables, count, gld_flags)))
302 DBUG_RETURN(NULL);
303
304 if (mysql_lock_tables(thd, sql_lock, flags))
305 {
306 /* Clear the lock type of all lock data to avoid reusage. */
307 reset_lock_data(sql_lock, 1);
308 if (!(gld_flags & GET_LOCK_ON_THD))
309 my_free(sql_lock);
310 sql_lock= 0;
311 }
312
313 track_table_access(thd, tables, count);
314
315 DBUG_RETURN(sql_lock);
316}
317
318/**
319 Lock tables based on a MYSQL_LOCK structure.
320
321 mysql_lock_tables()
322
323 @param thd The current thread.
324 @param sql_lock Tables that should be locked
325 @param flags See mysql_lock_tables() above
326
327 @return 0 ok
328 @return 1 error
329*/
330
331bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
332{
333 int rc= 1;
334 ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ?
335 LONG_TIMEOUT : thd->variables.lock_wait_timeout;
336 PSI_stage_info org_stage;
337 DBUG_ENTER("mysql_lock_tables(sql_lock)");
338
339 thd->backup_stage(&org_stage);
340 THD_STAGE_INFO(thd, stage_system_lock);
341 if (sql_lock->table_count && lock_external(thd, sql_lock->table,
342 sql_lock->table_count))
343 goto end;
344
345 THD_STAGE_INFO(thd, stage_table_lock);
346
347 /* Copy the lock data array. thr_multi_lock() reorders its contents. */
348 memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
349 sql_lock->lock_count * sizeof(*sql_lock->locks));
350
351 /* Lock on the copied half of the lock data array. */
352 rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
353 sql_lock->lock_count,
354 sql_lock->lock_count,
355 &thd->lock_info, timeout)];
356 if (rc && sql_lock->table_count)
357 (void) unlock_external(thd, sql_lock->table, sql_lock->table_count);
358
359end:
360 THD_STAGE_INFO(thd, org_stage);
361
362 if (thd->killed)
363 {
364 thd->send_kill_message();
365 if (!rc)
366 {
367 mysql_unlock_tables(thd, sql_lock, 0);
368 THD_STAGE_INFO(thd, stage_after_table_lock);
369 }
370 rc= 1;
371 }
372 else if (rc > 1)
373 my_error(rc, MYF(0));
374
375 thd->set_time_after_lock();
376 DBUG_RETURN(rc);
377}
378
379
380static int lock_external(THD *thd, TABLE **tables, uint count)
381{
382 uint i;
383 int lock_type,error;
384 DBUG_ENTER("lock_external");
385
386 DBUG_PRINT("info", ("count %d", count));
387 for (i=1 ; i <= count ; i++, tables++)
388 {
389 DBUG_ASSERT((*tables)->reginfo.lock_type >= TL_READ);
390 lock_type=F_WRLCK; /* Lock exclusive */
391 if ((*tables)->db_stat & HA_READ_ONLY ||
392 ((*tables)->reginfo.lock_type >= TL_READ &&
393 (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
394 lock_type=F_RDLCK;
395
396 if (unlikely((error=(*tables)->file->ha_external_lock(thd,lock_type))))
397 {
398 (*tables)->file->print_error(error, MYF(0));
399 while (--i)
400 {
401 tables--;
402 (*tables)->file->ha_external_lock(thd, F_UNLCK);
403 (*tables)->current_lock=F_UNLCK;
404 }
405 DBUG_RETURN(error);
406 }
407 else
408 {
409 (*tables)->current_lock= lock_type;
410 }
411 }
412 DBUG_RETURN(0);
413}
414
415
416void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
417{
418 mysql_unlock_tables(thd, sql_lock,
419 (thd->variables.option_bits & OPTION_TABLE_LOCK) ||
420 !(sql_lock->flags & GET_LOCK_ON_THD));
421}
422
423
424void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
425{
426 bool errors= thd->is_error();
427 PSI_stage_info org_stage;
428 DBUG_ENTER("mysql_unlock_tables");
429
430 thd->backup_stage(&org_stage);
431 THD_STAGE_INFO(thd, stage_unlocking_tables);
432
433 if (sql_lock->table_count)
434 unlock_external(thd, sql_lock->table, sql_lock->table_count);
435 if (sql_lock->lock_count)
436 thr_multi_unlock(sql_lock->locks, sql_lock->lock_count, 0);
437 if (free_lock)
438 {
439 DBUG_ASSERT(!(sql_lock->flags & GET_LOCK_ON_THD));
440 my_free(sql_lock);
441 }
442 if (likely(!errors))
443 thd->clear_error();
444 THD_STAGE_INFO(thd, org_stage);
445 DBUG_VOID_RETURN;
446}
447
448/**
449 Unlock some of the tables locked by mysql_lock_tables.
450
451 This will work even if get_lock_data fails (next unlock will free all)
452*/
453
454void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag)
455{
456 MYSQL_LOCK *sql_lock=
457 get_lock_data(thd, table, count, GET_LOCK_UNLOCK | GET_LOCK_ON_THD | flag);
458 if (sql_lock)
459 mysql_unlock_tables(thd, sql_lock, 0);
460}
461
462
463/**
464 unlock all tables locked for read.
465*/
466
467void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
468{
469 uint i,found;
470 DBUG_ENTER("mysql_unlock_read_tables");
471
472 /* Call external lock for all tables to be unlocked */
473
474 /* Move all write locked tables first */
475 TABLE **table=sql_lock->table;
476 for (i=found=0 ; i < sql_lock->table_count ; i++)
477 {
478 DBUG_ASSERT(sql_lock->table[i]->lock_position == i);
479 if ((uint) sql_lock->table[i]->reginfo.lock_type > TL_WRITE_ALLOW_WRITE)
480 {
481 swap_variables(TABLE *, *table, sql_lock->table[i]);
482 table++;
483 found++;
484 }
485 }
486 /* Unlock all read locked tables */
487 if (i != found)
488 {
489 (void) unlock_external(thd,table,i-found);
490 sql_lock->table_count=found;
491 }
492
493 /* Call thr_unlock() for all tables to be unlocked */
494
495 /* Move all write locks first */
496 THR_LOCK_DATA **lock=sql_lock->locks;
497 for (i=found=0 ; i < sql_lock->lock_count ; i++)
498 {
499 if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_WRITE)
500 {
501 swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
502 lock++;
503 found++;
504 }
505 }
506 /* unlock the read locked tables */
507 if (i != found)
508 {
509 thr_multi_unlock(lock, i-found, 0);
510 sql_lock->lock_count= found;
511 }
512
513 /* Fix the lock positions in TABLE */
514 table= sql_lock->table;
515 found= 0;
516 for (i= 0; i < sql_lock->table_count; i++)
517 {
518 TABLE *tbl= *table;
519 tbl->lock_position= (uint) (table - sql_lock->table);
520 tbl->lock_data_start= found;
521 found+= tbl->lock_count;
522 table++;
523 }
524 DBUG_VOID_RETURN;
525}
526
527
528/**
529 Try to find the table in the list of locked tables.
530 In case of success, unlock the table and remove it from this list.
531 If a table has more than one lock instance, removes them all.
532
533 @param thd thread context
534 @param locked list of locked tables
535 @param table the table to unlock
536*/
537
538void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
539{
540 if (locked)
541 {
542 uint i;
543 for (i=0; i < locked->table_count; i++)
544 {
545 if (locked->table[i] == table)
546 {
547 uint j, removed_locks, old_tables;
548 TABLE *tbl;
549 uint lock_data_end;
550
551 DBUG_ASSERT(table->lock_position == i);
552
553 /* Unlock the table. */
554 mysql_unlock_some_tables(thd, &table, /* table count */ 1, 0);
555
556 /* Decrement table_count in advance, making below expressions easier */
557 old_tables= --locked->table_count;
558
559 /* The table has 'removed_locks' lock data elements in locked->locks */
560 removed_locks= table->lock_count;
561
562 /* Move down all table pointers above 'i'. */
563 bmove((char*) (locked->table+i),
564 (char*) (locked->table+i+1),
565 (old_tables - i) * sizeof(TABLE*));
566
567 lock_data_end= table->lock_data_start + table->lock_count;
568 /* Move down all lock data pointers above 'table->lock_data_end-1' */
569 bmove((char*) (locked->locks + table->lock_data_start),
570 (char*) (locked->locks + lock_data_end),
571 (locked->lock_count - lock_data_end) *
572 sizeof(THR_LOCK_DATA*));
573
574 /*
575 Fix moved table elements.
576 lock_position is the index in the 'locked->table' array,
577 it must be fixed by one.
578 table->lock_data_start is pointer to the lock data for this table
579 in the 'locked->locks' array, they must be fixed by 'removed_locks',
580 the lock data count of the removed table.
581 */
582 for (j= i ; j < old_tables; j++)
583 {
584 tbl= locked->table[j];
585 tbl->lock_position--;
586 DBUG_ASSERT(tbl->lock_position == j);
587 tbl->lock_data_start-= removed_locks;
588 }
589
590 /* Finally adjust lock_count. */
591 locked->lock_count-= removed_locks;
592 break;
593 }
594 }
595 }
596}
597
598
599/** Abort all other threads waiting to get lock in table. */
600
601void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
602{
603 MYSQL_LOCK *locked;
604 DBUG_ENTER("mysql_lock_abort");
605
606 if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK | GET_LOCK_ON_THD)))
607 {
608 for (uint i=0; i < locked->lock_count; i++)
609 thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
610 }
611 DBUG_VOID_RETURN;
612}
613
614
615/**
616 Abort one thread / table combination.
617
618 @param thd Thread handler
619 @param table Table that should be removed from lock queue
620
621 @retval
622 0 Table was not locked by another thread
623 @retval
624 1 Table was locked by at least one other thread
625*/
626
627bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
628{
629 MYSQL_LOCK *locked;
630 bool result= FALSE;
631 DBUG_ENTER("mysql_lock_abort_for_thread");
632
633 if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK | GET_LOCK_ON_THD)))
634 {
635 for (uint i=0; i < locked->lock_count; i++)
636 {
637 if (thr_abort_locks_for_thread(locked->locks[i]->lock,
638 table->in_use->thread_id))
639 result= TRUE;
640 }
641 }
642 DBUG_RETURN(result);
643}
644
645
646/**
647 Merge two thr_lock:s
648 mysql_lock_merge()
649
650 @param a Original locks
651 @param b New locks
652
653 @retval New lock structure that contains a and b
654
655 @note
656 a and b are freed with my_free()
657*/
658
659MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
660{
661 MYSQL_LOCK *sql_lock;
662 TABLE **table, **end_table;
663 DBUG_ENTER("mysql_lock_merge");
664 DBUG_PRINT("enter", ("a->lock_count: %u b->lock_count: %u",
665 a->lock_count, b->lock_count));
666
667 if (!(sql_lock= (MYSQL_LOCK*)
668 my_malloc(sizeof(*sql_lock)+
669 sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) +
670 sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
671 DBUG_RETURN(0); // Fatal error
672 sql_lock->lock_count=a->lock_count+b->lock_count;
673 sql_lock->table_count=a->table_count+b->table_count;
674 sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
675 sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count*2);
676 sql_lock->flags= 0;
677 memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
678 memcpy(sql_lock->locks+a->lock_count,b->locks,
679 b->lock_count*sizeof(*b->locks));
680 memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
681 memcpy(sql_lock->table+a->table_count,b->table,
682 b->table_count*sizeof(*b->table));
683
684 /*
685 Now adjust lock_position and lock_data_start for all objects that was
686 moved in 'b' (as there is now all objects in 'a' before these).
687 */
688 for (table= sql_lock->table + a->table_count,
689 end_table= table + b->table_count;
690 table < end_table;
691 table++)
692 {
693 (*table)->lock_position+= a->table_count;
694 (*table)->lock_data_start+= a->lock_count;
695 }
696
697 /*
698 Ensure that locks of the same tables share same data structures if we
699 reopen a table that is already open. This can happen for example with
700 MERGE tables.
701 */
702
703 /* Copy the lock data array. thr_merge_lock() reorders its content */
704 memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
705 sql_lock->lock_count * sizeof(*sql_lock->locks));
706 thr_merge_locks(sql_lock->locks + sql_lock->lock_count,
707 a->lock_count, b->lock_count);
708
709 /* Delete old, not needed locks */
710 my_free(a);
711 my_free(b);
712 DBUG_RETURN(sql_lock);
713}
714
715
716/** Unlock a set of external. */
717
718static int unlock_external(THD *thd, TABLE **table,uint count)
719{
720 int error,error_code;
721 DBUG_ENTER("unlock_external");
722
723 error_code=0;
724 do
725 {
726 if ((*table)->current_lock != F_UNLCK)
727 {
728 (*table)->current_lock = F_UNLCK;
729 if (unlikely((error=(*table)->file->ha_external_lock(thd, F_UNLCK))))
730 {
731 error_code= error;
732 (*table)->file->print_error(error, MYF(0));
733 }
734 }
735 table++;
736 } while (--count);
737 DBUG_RETURN(error_code);
738}
739
740
741/**
742 Get lock structures from table structs and initialize locks.
743
744 @param thd Thread handler
745 @param table_ptr Pointer to tables that should be locks
746 @param flags One of:
747 - GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
748 - GET_LOCK_STORE_LOCKS : Store lock info in TABLE
749 - GET_LOCK_SKIP_SEQUENCES : Ignore sequences (for temporary unlock)
750 - GET_LOCK_ON_THD : Store lock in thd->mem_root
751*/
752
753MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
754{
755 uint i,lock_count,table_count;
756 MYSQL_LOCK *sql_lock;
757 THR_LOCK_DATA **locks, **locks_buf;
758 TABLE **to, **table_buf;
759 DBUG_ENTER("get_lock_data");
760
761 DBUG_PRINT("info", ("count %d", count));
762
763 for (i=lock_count=table_count=0 ; i < count ; i++)
764 {
765 TABLE *t= table_ptr[i];
766
767 if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE &&
768 t->s->tmp_table != INTERNAL_TMP_TABLE &&
769 (!(flags & GET_LOCK_SKIP_SEQUENCES) || t->s->sequence == 0))
770 {
771 lock_count+= t->file->lock_count();
772 table_count++;
773 }
774 }
775
776 /*
777 Allocating twice the number of pointers for lock data for use in
778 thr_multi_lock(). This function reorders the lock data, but cannot
779 update the table values. So the second part of the array is copied
780 from the first part immediately before calling thr_multi_lock().
781 */
782 size_t amount= sizeof(*sql_lock) +
783 sizeof(THR_LOCK_DATA*) * lock_count * 2 +
784 sizeof(table_ptr) * table_count;
785 if (!(sql_lock= (MYSQL_LOCK*) (flags & GET_LOCK_ON_THD ?
786 thd->alloc(amount) :
787 my_malloc(amount, MYF(0)))))
788 DBUG_RETURN(0);
789 locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
790 to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2);
791 sql_lock->table_count= table_count;
792 sql_lock->flags= flags;
793
794 for (i=0 ; i < count ; i++)
795 {
796 TABLE *table;
797 enum thr_lock_type lock_type;
798 THR_LOCK_DATA **locks_start;
799 table= table_ptr[i];
800 if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE ||
801 table->s->tmp_table == INTERNAL_TMP_TABLE ||
802 ((flags & GET_LOCK_SKIP_SEQUENCES) && table->s->sequence))
803 continue;
804 lock_type= table->reginfo.lock_type;
805 DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
806 locks_start= locks;
807 locks= table->file->store_lock(thd, locks,
808 (flags & GET_LOCK_ACTION_MASK) == GET_LOCK_UNLOCK ? TL_IGNORE :
809 lock_type);
810 if ((flags & GET_LOCK_ACTION_MASK) == GET_LOCK_STORE_LOCKS)
811 {
812 table->lock_position= (uint) (to - table_buf);
813 table->lock_data_start= (uint) (locks_start - locks_buf);
814 table->lock_count= (uint) (locks - locks_start);
815 }
816 *to++= table;
817 if (locks)
818 {
819 for ( ; locks_start != locks ; locks_start++)
820 {
821 (*locks_start)->debug_print_param= (void *) table;
822 (*locks_start)->m_psi= table->file->m_psi;
823 (*locks_start)->lock->name= table->alias.c_ptr();
824 (*locks_start)->org_type= (*locks_start)->type;
825 }
826 }
827 }
828 /*
829 We do not use 'lock_count', because there are cases where store_lock()
830 returns less locks than lock_count() claimed. This can happen when
831 a FLUSH TABLES tries to abort locks from a MERGE table of another
832 thread. When that thread has just opened the table, but not yet
833 attached its children, it cannot return the locks. lock_count()
834 always returns the number of locks that an attached table has.
835 This is done to avoid the reverse situation: If lock_count() would
836 return 0 for a non-attached MERGE table, and that table becomes
837 attached between the calls to lock_count() and store_lock(), then
838 we would have allocated too little memory for the lock data. Now
839 we may allocate too much, but better safe than memory overrun.
840 And in the FLUSH case, the memory is released quickly anyway.
841 */
842 sql_lock->lock_count= (uint)(locks - locks_buf);
843 DBUG_ASSERT(sql_lock->lock_count <= lock_count);
844 DBUG_PRINT("info", ("sql_lock->table_count %d sql_lock->lock_count %d",
845 sql_lock->table_count, sql_lock->lock_count));
846 DBUG_RETURN(sql_lock);
847}
848
849
850/**
851 Obtain an exclusive metadata lock on a schema name.
852
853 @param thd Thread handle.
854 @param db The database name.
855
856 To avoid deadlocks, we do not try to obtain exclusive metadata
857 locks in LOCK TABLES mode, since in this mode there may be
858 other metadata locks already taken by the current connection,
859 and we must not wait for MDL locks while holding locks.
860
861 @retval FALSE Success.
862 @retval TRUE Failure: we're in LOCK TABLES mode, or out of memory,
863 or this connection was killed.
864*/
865
866bool lock_schema_name(THD *thd, const char *db)
867{
868 MDL_request_list mdl_requests;
869 MDL_request global_request;
870 MDL_request mdl_request;
871
872 if (thd->locked_tables_mode)
873 {
874 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
875 ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
876 return TRUE;
877 }
878
879 if (thd->global_read_lock.can_acquire_protection())
880 return TRUE;
881 global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
882 MDL_STATEMENT);
883 mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE, MDL_TRANSACTION);
884
885 mdl_requests.push_front(&mdl_request);
886 mdl_requests.push_front(&global_request);
887
888 if (thd->mdl_context.acquire_locks(&mdl_requests,
889 thd->variables.lock_wait_timeout))
890 return TRUE;
891
892 DEBUG_SYNC(thd, "after_wait_locked_schema_name");
893 return FALSE;
894}
895
896
897/**
898 Obtain an exclusive metadata lock on an object name.
899
900 @param thd Thread handle.
901 @param mdl_type Object type (currently functions, procedures
902 and events can be name-locked).
903 @param db The schema the object belongs to.
904 @param name Object name in the schema.
905
906 This function assumes that no metadata locks were acquired
907 before calling it. It is enforced by asserts in MDL_context::acquire_locks().
908 To avoid deadlocks, we do not try to obtain exclusive metadata
909 locks in LOCK TABLES mode, since in this mode there may be
910 other metadata locks already taken by the current connection,
911 and we must not wait for MDL locks while holding locks.
912
913 @retval FALSE Success.
914 @retval TRUE Failure: we're in LOCK TABLES mode, or out of memory,
915 or this connection was killed.
916*/
917
918bool lock_object_name(THD *thd, MDL_key::enum_mdl_namespace mdl_type,
919 const char *db, const char *name)
920{
921 MDL_request_list mdl_requests;
922 MDL_request global_request;
923 MDL_request schema_request;
924 MDL_request mdl_request;
925
926 DBUG_SLOW_ASSERT(ok_for_lower_case_names(db));
927
928 if (thd->locked_tables_mode)
929 {
930 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
931 ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
932 return TRUE;
933 }
934
935 DBUG_ASSERT(name);
936 DEBUG_SYNC(thd, "before_wait_locked_pname");
937
938 if (thd->global_read_lock.can_acquire_protection())
939 return TRUE;
940 global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
941 MDL_STATEMENT);
942 schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE,
943 MDL_TRANSACTION);
944 mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE, MDL_TRANSACTION);
945
946 mdl_requests.push_front(&mdl_request);
947 mdl_requests.push_front(&schema_request);
948 mdl_requests.push_front(&global_request);
949
950 if (thd->mdl_context.acquire_locks(&mdl_requests,
951 thd->variables.lock_wait_timeout))
952 return TRUE;
953
954 DEBUG_SYNC(thd, "after_wait_locked_pname");
955 return FALSE;
956}
957
958
959/****************************************************************************
960 Handling of global read locks
961
962 Global read lock is implemented using metadata lock infrastructure.
963
964 Taking the global read lock is TWO steps (2nd step is optional; without
965 it, COMMIT of existing transactions will be allowed):
966 lock_global_read_lock() THEN make_global_read_lock_block_commit().
967
968 How blocking of threads by global read lock is achieved: that's
969 semi-automatic. We assume that any statement which should be blocked
970 by global read lock will either open and acquires write-lock on tables
971 or acquires metadata locks on objects it is going to modify. For any
972 such statement global IX metadata lock is automatically acquired for
973 its duration (in case of LOCK TABLES until end of LOCK TABLES mode).
974 And lock_global_read_lock() simply acquires global S metadata lock
975 and thus prohibits execution of statements which modify data (unless
976 they modify only temporary tables). If deadlock happens it is detected
977 by MDL subsystem and resolved in the standard fashion (by backing-off
978 metadata locks acquired so far and restarting open tables process
979 if possible).
980
981 Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
982 to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
983 log.
984
985 Why getting the global read lock is two steps and not one. Because FLUSH
986 TABLES WITH READ LOCK needs to insert one other step between the two:
987 flushing tables. So the order is
988 1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
989 all new updates)
990 2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
991 currently opened and being updated to close (so it's possible that there is
992 a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
993 READ LOCK is, too).
994 3) make_global_read_lock_block_commit().
995 If we have merged 1) and 3) into 1), we would have had this deadlock:
996 imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
997 table t.
998 thd1: SELECT * FROM t FOR UPDATE;
999 thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
1000 thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
1001 table instance of thd2
1002 thd1: COMMIT; # blocked by thd3.
1003 thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
1004
1005 Note that we need to support that one thread does
1006 FLUSH TABLES WITH READ LOCK; and then COMMIT;
1007 (that's what innobackup does, for some good reason).
1008 So in this exceptional case the COMMIT should not be blocked by the FLUSH
1009 TABLES WITH READ LOCK.
1010
1011****************************************************************************/
1012
1013/**
1014 Take global read lock, wait if there is protection against lock.
1015
1016 If the global read lock is already taken by this thread, then nothing is done.
1017
1018 See also "Handling of global read locks" above.
1019
1020 @param thd Reference to thread.
1021
1022 @retval False Success, global read lock set, commits are NOT blocked.
1023 @retval True Failure, thread was killed.
1024*/
1025
1026bool Global_read_lock::lock_global_read_lock(THD *thd)
1027{
1028 DBUG_ENTER("lock_global_read_lock");
1029
1030 if (!m_state)
1031 {
1032 MDL_request mdl_request;
1033
1034 DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
1035 MDL_SHARED));
1036 mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED, MDL_EXPLICIT);
1037
1038 if (thd->mdl_context.acquire_lock(&mdl_request,
1039 thd->variables.lock_wait_timeout))
1040 DBUG_RETURN(1);
1041
1042 m_mdl_global_shared_lock= mdl_request.ticket;
1043 m_state= GRL_ACQUIRED;
1044 }
1045 /*
1046 We DON'T set global_read_lock_blocks_commit now, it will be set after
1047 tables are flushed (as the present function serves for FLUSH TABLES WITH
1048 READ LOCK only). Doing things in this order is necessary to avoid
1049 deadlocks (we must allow COMMIT until all tables are closed; we should not
1050 forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
1051 UPDATE and one does FLUSH TABLES WITH READ LOCK).
1052 */
1053 DBUG_RETURN(0);
1054}
1055
1056
1057/**
1058 Unlock global read lock.
1059
1060 Commits may or may not be blocked when this function is called.
1061
1062 See also "Handling of global read locks" above.
1063
1064 @param thd Reference to thread.
1065*/
1066
1067void Global_read_lock::unlock_global_read_lock(THD *thd)
1068{
1069 DBUG_ENTER("unlock_global_read_lock");
1070
1071 DBUG_ASSERT(m_mdl_global_shared_lock && m_state);
1072
1073 if (thd->global_disable_checkpoint)
1074 {
1075 thd->global_disable_checkpoint= 0;
1076 if (!--global_disable_checkpoint)
1077 {
1078 ha_checkpoint_state(0); // Enable checkpoints
1079 }
1080 }
1081
1082 if (m_mdl_blocks_commits_lock)
1083 {
1084 thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
1085 m_mdl_blocks_commits_lock= NULL;
1086#ifdef WITH_WSREP
1087 if (WSREP(thd) || wsrep_node_is_donor())
1088 {
1089 wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
1090 wsrep->resume(wsrep);
1091 /* resync here only if we did implicit desync earlier */
1092 if (!wsrep_desync && wsrep_node_is_synced())
1093 {
1094 int ret = wsrep->resync(wsrep);
1095 if (ret != WSREP_OK)
1096 {
1097 WSREP_WARN("resync failed %d for FTWRL: db: %s, query: %s",
1098 ret, thd->get_db(), thd->query());
1099 DBUG_VOID_RETURN;
1100 }
1101 }
1102 }
1103#endif /* WITH_WSREP */
1104 }
1105 thd->mdl_context.release_lock(m_mdl_global_shared_lock);
1106 m_mdl_global_shared_lock= NULL;
1107 m_state= GRL_NONE;
1108
1109 DBUG_VOID_RETURN;
1110}
1111
1112
1113/**
1114 Make global read lock also block commits.
1115
1116 The scenario is:
1117 - This thread has the global read lock.
1118 - Global read lock blocking of commits is not set.
1119
1120 See also "Handling of global read locks" above.
1121
1122 @param thd Reference to thread.
1123
1124 @retval False Success, global read lock set, commits are blocked.
1125 @retval True Failure, thread was killed.
1126*/
1127
1128bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
1129{
1130 MDL_request mdl_request;
1131 DBUG_ENTER("make_global_read_lock_block_commit");
1132 /*
1133 If we didn't succeed lock_global_read_lock(), or if we already suceeded
1134 make_global_read_lock_block_commit(), do nothing.
1135 */
1136
1137 if (m_state != GRL_ACQUIRED)
1138 DBUG_RETURN(0);
1139
1140#ifdef WITH_WSREP
1141 if (WSREP(thd) && m_mdl_blocks_commits_lock)
1142 {
1143 WSREP_DEBUG("GRL was in block commit mode when entering "
1144 "make_global_read_lock_block_commit");
1145 DBUG_RETURN(FALSE);
1146 }
1147#endif /* WITH_WSREP */
1148
1149 mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT);
1150
1151 if (thd->mdl_context.acquire_lock(&mdl_request,
1152 thd->variables.lock_wait_timeout))
1153 DBUG_RETURN(TRUE);
1154
1155 m_mdl_blocks_commits_lock= mdl_request.ticket;
1156 m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
1157
1158#ifdef WITH_WSREP
1159 /* Native threads should bail out before wsrep oprations to follow.
1160 Donor servicing thread is an exception, it should pause provider but not desync,
1161 as it is already desynced in donor state
1162 */
1163 if (!WSREP(thd) && !wsrep_node_is_donor())
1164 {
1165 DBUG_RETURN(FALSE);
1166 }
1167
1168 /* if already desynced or donor, avoid double desyncing
1169 if not in PC and synced, desyncing is not possible either
1170 */
1171 if (wsrep_desync || !wsrep_node_is_synced())
1172 {
1173 WSREP_DEBUG("desync set upfont, skipping implicit desync for FTWRL: %d",
1174 wsrep_desync);
1175 }
1176 else
1177 {
1178 int rcode;
1179 WSREP_DEBUG("running implicit desync for node");
1180 rcode = wsrep->desync(wsrep);
1181 if (rcode != WSREP_OK)
1182 {
1183 WSREP_WARN("FTWRL desync failed %d for schema: %s, query: %s",
1184 rcode, thd->get_db(), thd->query());
1185 my_message(ER_LOCK_DEADLOCK, "wsrep desync failed for FTWRL", MYF(0));
1186 DBUG_RETURN(TRUE);
1187 }
1188 }
1189
1190 long long ret = wsrep->pause(wsrep);
1191 if (ret >= 0)
1192 {
1193 wsrep_locked_seqno= ret;
1194 }
1195 else if (ret != -ENOSYS) /* -ENOSYS - no provider */
1196 {
1197 long long ret = wsrep->pause(wsrep);
1198 if (ret >= 0)
1199 {
1200 wsrep_locked_seqno= ret;
1201 }
1202 else if (ret != -ENOSYS) /* -ENOSYS - no provider */
1203 {
1204 WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret));
1205
1206 DBUG_ASSERT(m_mdl_blocks_commits_lock == NULL);
1207 wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
1208 my_error(ER_LOCK_DEADLOCK, MYF(0));
1209 DBUG_RETURN(TRUE);
1210 }
1211 }
1212#endif /* WITH_WSREP */
1213 DBUG_RETURN(FALSE);
1214}
1215
1216
1217/**
1218 Set explicit duration for metadata locks which are used to implement GRL.
1219
1220 @param thd Reference to thread.
1221*/
1222
1223void Global_read_lock::set_explicit_lock_duration(THD *thd)
1224{
1225 if (m_mdl_global_shared_lock)
1226 thd->mdl_context.set_lock_duration(m_mdl_global_shared_lock, MDL_EXPLICIT);
1227 if (m_mdl_blocks_commits_lock)
1228 thd->mdl_context.set_lock_duration(m_mdl_blocks_commits_lock, MDL_EXPLICIT);
1229}
1230
1231/**
1232 @} (end of group Locking)
1233*/
1234