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