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