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