1 /* Copyright (c) 2007, 2012, 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 as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software Foundation,
14 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
15
16
17 #include "mariadb.h"
18 #include "sql_class.h"
19 #include "debug_sync.h"
20 #include "sql_array.h"
21 #include "rpl_rli.h"
22 #include <lf.h>
23 #include "unireg.h"
24 #include <mysql/plugin.h>
25 #include <mysql/service_thd_wait.h>
26 #include <mysql/psi/mysql_stage.h>
27 #ifdef HAVE_PSI_INTERFACE
28 static PSI_mutex_key key_MDL_wait_LOCK_wait_status;
29
30 static PSI_mutex_info all_mdl_mutexes[]=
31 {
32 { &key_MDL_wait_LOCK_wait_status, "MDL_wait::LOCK_wait_status", 0}
33 };
34
35 static PSI_rwlock_key key_MDL_lock_rwlock;
36 static PSI_rwlock_key key_MDL_context_LOCK_waiting_for;
37
38 static PSI_rwlock_info all_mdl_rwlocks[]=
39 {
40 { &key_MDL_lock_rwlock, "MDL_lock::rwlock", 0},
41 { &key_MDL_context_LOCK_waiting_for, "MDL_context::LOCK_waiting_for", 0}
42 };
43
44 static PSI_cond_key key_MDL_wait_COND_wait_status;
45
46 static PSI_cond_info all_mdl_conds[]=
47 {
48 { &key_MDL_wait_COND_wait_status, "MDL_context::COND_wait_status", 0}
49 };
50
51 /**
52 Initialise all the performance schema instrumentation points
53 used by the MDL subsystem.
54 */
init_mdl_psi_keys(void)55 static void init_mdl_psi_keys(void)
56 {
57 int count;
58
59 count= array_elements(all_mdl_mutexes);
60 mysql_mutex_register("sql", all_mdl_mutexes, count);
61
62 count= array_elements(all_mdl_rwlocks);
63 mysql_rwlock_register("sql", all_mdl_rwlocks, count);
64
65 count= array_elements(all_mdl_conds);
66 mysql_cond_register("sql", all_mdl_conds, count);
67
68 MDL_key::init_psi_keys();
69 }
70 #endif /* HAVE_PSI_INTERFACE */
71
72
73 /**
74 Thread state names to be used in case when we have to wait on resource
75 belonging to certain namespace.
76 */
77
78 PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
79 {
80 {0, "Waiting for backup lock", 0},
81 {0, "Waiting for schema metadata lock", 0},
82 {0, "Waiting for table metadata lock", 0},
83 {0, "Waiting for stored function metadata lock", 0},
84 {0, "Waiting for stored procedure metadata lock", 0},
85 {0, "Waiting for stored package body metadata lock", 0},
86 {0, "Waiting for trigger metadata lock", 0},
87 {0, "Waiting for event metadata lock", 0},
88 {0, "User lock", 0} /* Be compatible with old status. */
89 };
90
91
92 static const LEX_STRING lock_types[]=
93 {
94 { C_STRING_WITH_LEN("MDL_INTENTION_EXCLUSIVE") },
95 { C_STRING_WITH_LEN("MDL_SHARED") },
96 { C_STRING_WITH_LEN("MDL_SHARED_HIGH_PRIO") },
97 { C_STRING_WITH_LEN("MDL_SHARED_READ") },
98 { C_STRING_WITH_LEN("MDL_SHARED_WRITE") },
99 { C_STRING_WITH_LEN("MDL_SHARED_UPGRADABLE") },
100 { C_STRING_WITH_LEN("MDL_SHARED_READ_ONLY") },
101 { C_STRING_WITH_LEN("MDL_SHARED_NO_WRITE") },
102 { C_STRING_WITH_LEN("MDL_SHARED_NO_READ_WRITE") },
103 { C_STRING_WITH_LEN("MDL_EXCLUSIVE") },
104 };
105
106
107 static const LEX_STRING backup_lock_types[]=
108 {
109 { C_STRING_WITH_LEN("MDL_BACKUP_START") },
110 { C_STRING_WITH_LEN("MDL_BACKUP_FLUSH") },
111 { C_STRING_WITH_LEN("MDL_BACKUP_WAIT_FLUSH") },
112 { C_STRING_WITH_LEN("MDL_BACKUP_WAIT_DDL") },
113 { C_STRING_WITH_LEN("MDL_BACKUP_WAIT_COMMIT") },
114 { C_STRING_WITH_LEN("MDL_BACKUP_FTWRL1") },
115 { C_STRING_WITH_LEN("MDL_BACKUP_FTWRL2") },
116 { C_STRING_WITH_LEN("MDL_BACKUP_DML") },
117 { C_STRING_WITH_LEN("MDL_BACKUP_TRANS_DML") },
118 { C_STRING_WITH_LEN("MDL_BACKUP_SYS_DML") },
119 { C_STRING_WITH_LEN("MDL_BACKUP_DDL") },
120 { C_STRING_WITH_LEN("MDL_BACKUP_BLOCK_DDL") },
121 { C_STRING_WITH_LEN("MDL_BACKUP_ALTER_COPY") },
122 { C_STRING_WITH_LEN("MDL_BACKUP_COMMIT") }
123 };
124
125
126 #ifdef HAVE_PSI_INTERFACE
init_psi_keys()127 void MDL_key::init_psi_keys()
128 {
129 int i;
130 int count;
131 PSI_stage_info *info __attribute__((unused));
132
133 count= array_elements(MDL_key::m_namespace_to_wait_state_name);
134 for (i= 0; i<count; i++)
135 {
136 /* mysql_stage_register wants an array of pointers, registering 1 by 1. */
137 info= & MDL_key::m_namespace_to_wait_state_name[i];
138 mysql_stage_register("sql", &info, 1);
139 }
140 }
141 #endif
142
143 static bool mdl_initialized= 0;
144
145
146 /**
147 A collection of all MDL locks. A singleton,
148 there is only one instance of the map in the server.
149 */
150
151 class MDL_map
152 {
153 public:
154 void init();
155 void destroy();
156 MDL_lock *find_or_insert(LF_PINS *pins, const MDL_key *key);
157 unsigned long get_lock_owner(LF_PINS *pins, const MDL_key *key);
158 void remove(LF_PINS *pins, MDL_lock *lock);
get_pins()159 LF_PINS *get_pins() { return lf_hash_get_pins(&m_locks); }
160 private:
161 LF_HASH m_locks; /**< All acquired locks in the server. */
162 /** Pre-allocated MDL_lock object for BACKUP namespace. */
163 MDL_lock *m_backup_lock;
164 friend int mdl_iterate(mdl_iterator_callback, void *);
165 };
166
167
168 /**
169 A context of the recursive traversal through all contexts
170 in all sessions in search for deadlock.
171 */
172
173 class Deadlock_detection_visitor: public MDL_wait_for_graph_visitor
174 {
175 public:
Deadlock_detection_visitor(MDL_context * start_node_arg)176 Deadlock_detection_visitor(MDL_context *start_node_arg)
177 : m_start_node(start_node_arg),
178 m_victim(NULL),
179 m_current_search_depth(0),
180 m_found_deadlock(FALSE)
181 {}
182 virtual bool enter_node(MDL_context *node);
183 virtual void leave_node(MDL_context *node);
184
185 virtual bool inspect_edge(MDL_context *dest);
186
get_victim() const187 MDL_context *get_victim() const { return m_victim; }
188 private:
189 /**
190 Change the deadlock victim to a new one if it has lower deadlock
191 weight.
192 */
193 void opt_change_victim_to(MDL_context *new_victim);
194 private:
195 /**
196 The context which has initiated the search. There
197 can be multiple searches happening in parallel at the same time.
198 */
199 MDL_context *m_start_node;
200 /** If a deadlock is found, the context that identifies the victim. */
201 MDL_context *m_victim;
202 /** Set to the 0 at start. Increased whenever
203 we descend into another MDL context (aka traverse to the next
204 wait-for graph node). When MAX_SEARCH_DEPTH is reached, we
205 assume that a deadlock is found, even if we have not found a
206 loop.
207 */
208 uint m_current_search_depth;
209 /** TRUE if we found a deadlock. */
210 bool m_found_deadlock;
211 /**
212 Maximum depth for deadlock searches. After this depth is
213 achieved we will unconditionally declare that there is a
214 deadlock.
215
216 @note This depth should be small enough to avoid stack
217 being exhausted by recursive search algorithm.
218
219 TODO: Find out what is the optimal value for this parameter.
220 Current value is safe, but probably sub-optimal,
221 as there is an anecdotal evidence that real-life
222 deadlocks are even shorter typically.
223 */
224 static const uint MAX_SEARCH_DEPTH= 32;
225 };
226
227 #ifndef DBUG_OFF
228
229 /*
230 Print a list of all locks to DBUG trace to help with debugging
231 */
232
mdl_dbug_print_lock(MDL_ticket * mdl_ticket,void * arg,bool granted)233 static int mdl_dbug_print_lock(MDL_ticket *mdl_ticket, void *arg, bool granted)
234 {
235 String *tmp= (String*) arg;
236 char buffer[128];
237 MDL_key *mdl_key= mdl_ticket->get_key();
238 size_t length;
239 length= my_snprintf(buffer, sizeof(buffer)-1,
240 "\nname: %s db: %.*s key_name: %.*s (%s)",
241 mdl_ticket->get_type_name()->str,
242 (int) mdl_key->db_name_length(), mdl_key->db_name(),
243 (int) mdl_key->name_length(), mdl_key->name(),
244 granted ? "granted" : "waiting");
245 tmp->append(buffer, length);
246 return 0;
247 }
248
mdl_dbug_print_locks()249 const char *mdl_dbug_print_locks()
250 {
251 static String tmp;
252 mdl_iterate(mdl_dbug_print_lock, (void*) &tmp);
253 return tmp.c_ptr();
254 }
255 #endif /* DBUG_OFF */
256
257 /**
258 Enter a node of a wait-for graph. After
259 a node is entered, inspect_edge() will be called
260 for all wait-for destinations of this node. Then
261 leave_node() will be called.
262 We call "enter_node()" for all nodes we inspect,
263 including the starting node.
264
265 @retval TRUE Maximum search depth exceeded.
266 @retval FALSE OK.
267 */
268
enter_node(MDL_context * node)269 bool Deadlock_detection_visitor::enter_node(MDL_context *node)
270 {
271 m_found_deadlock= ++m_current_search_depth >= MAX_SEARCH_DEPTH;
272 if (m_found_deadlock)
273 {
274 DBUG_ASSERT(! m_victim);
275 opt_change_victim_to(node);
276 }
277 return m_found_deadlock;
278 }
279
280
281 /**
282 Done inspecting this node. Decrease the search
283 depth. If a deadlock is found, and we are
284 backtracking to the start node, optionally
285 change the deadlock victim to one with lower
286 deadlock weight.
287 */
288
leave_node(MDL_context * node)289 void Deadlock_detection_visitor::leave_node(MDL_context *node)
290 {
291 --m_current_search_depth;
292 if (m_found_deadlock)
293 opt_change_victim_to(node);
294 }
295
296
297 /**
298 Inspect a wait-for graph edge from one MDL context to another.
299
300 @retval TRUE A loop is found.
301 @retval FALSE No loop is found.
302 */
303
inspect_edge(MDL_context * node)304 bool Deadlock_detection_visitor::inspect_edge(MDL_context *node)
305 {
306 m_found_deadlock= node == m_start_node;
307 return m_found_deadlock;
308 }
309
310
311 /**
312 Change the deadlock victim to a new one if it has lower deadlock
313 weight.
314
315 @retval new_victim Victim is not changed.
316 @retval !new_victim New victim became the current.
317 */
318
319 void
opt_change_victim_to(MDL_context * new_victim)320 Deadlock_detection_visitor::opt_change_victim_to(MDL_context *new_victim)
321 {
322 if (m_victim == NULL ||
323 m_victim->get_deadlock_weight() >= new_victim->get_deadlock_weight())
324 {
325 /* Swap victims, unlock the old one. */
326 MDL_context *tmp= m_victim;
327 m_victim= new_victim;
328 m_victim->lock_deadlock_victim();
329 if (tmp)
330 tmp->unlock_deadlock_victim();
331 }
332 }
333
334
335 /**
336 Get a bit corresponding to enum_mdl_type value in a granted/waiting bitmaps
337 and compatibility matrices.
338 */
339
340 /**
341 The lock context. Created internally for an acquired lock.
342 For a given name, there exists only one MDL_lock instance,
343 and it exists only when the lock has been granted.
344 Can be seen as an MDL subsystem's version of TABLE_SHARE.
345
346 This is an abstract class which lacks information about
347 compatibility rules for lock types. They should be specified
348 in its descendants.
349 */
350
351 class MDL_lock
352 {
353 public:
354 typedef mdl_bitmap_t bitmap_t;
355
356 class Ticket_list
357 {
358 public:
359 typedef I_P_List<MDL_ticket,
360 I_P_List_adapter<MDL_ticket,
361 &MDL_ticket::next_in_lock,
362 &MDL_ticket::prev_in_lock>,
363 I_P_List_null_counter,
364 I_P_List_fast_push_back<MDL_ticket> >
365 List;
operator const List&() const366 operator const List &() const { return m_list; }
Ticket_list()367 Ticket_list() :m_bitmap(0) {}
368
369 void add_ticket(MDL_ticket *ticket);
370 void remove_ticket(MDL_ticket *ticket);
is_empty() const371 bool is_empty() const { return m_list.is_empty(); }
bitmap() const372 bitmap_t bitmap() const { return m_bitmap; }
373 private:
374 void clear_bit_if_not_in_list(enum_mdl_type type);
375 private:
376 /** List of tickets. */
377 List m_list;
378 /** Bitmap of types of tickets in this list. */
379 bitmap_t m_bitmap;
380 };
381
382 typedef Ticket_list::List::Iterator Ticket_iterator;
383
384
385 /**
386 Helper struct which defines how different types of locks are handled
387 for a specific MDL_lock. In practice we use only three strategies:
388 "backup" lock strategy for locks in BACKUP namespace, "scoped" lock
389 strategy for locks in SCHEMA namespace and "object" lock strategy for
390 all other namespaces.
391 */
392 struct MDL_lock_strategy
393 {
394 virtual const bitmap_t *incompatible_granted_types_bitmap() const = 0;
395 virtual const bitmap_t *incompatible_waiting_types_bitmap() const = 0;
396 virtual bool needs_notification(const MDL_ticket *ticket) const = 0;
397 virtual bool conflicting_locks(const MDL_ticket *ticket) const = 0;
398 virtual bitmap_t hog_lock_types_bitmap() const = 0;
~MDL_lock_strategyMDL_lock::MDL_lock_strategy399 virtual ~MDL_lock_strategy() {}
400 };
401
402
403 /**
404 An implementation of the scoped metadata lock. The only locking modes
405 which are supported at the moment are SHARED and INTENTION EXCLUSIVE
406 and EXCLUSIVE
407 */
408 struct MDL_scoped_lock : public MDL_lock_strategy
409 {
MDL_scoped_lockMDL_lock::MDL_scoped_lock410 MDL_scoped_lock() {}
incompatible_granted_types_bitmapMDL_lock::MDL_scoped_lock411 virtual const bitmap_t *incompatible_granted_types_bitmap() const
412 { return m_granted_incompatible; }
incompatible_waiting_types_bitmapMDL_lock::MDL_scoped_lock413 virtual const bitmap_t *incompatible_waiting_types_bitmap() const
414 { return m_waiting_incompatible; }
needs_notificationMDL_lock::MDL_scoped_lock415 virtual bool needs_notification(const MDL_ticket *ticket) const
416 { return (ticket->get_type() == MDL_SHARED); }
417
418 /**
419 Notify threads holding scoped IX locks which conflict with a pending
420 S lock.
421
422 Thread which holds global IX lock can be a handler thread for
423 insert delayed. We need to kill such threads in order to get
424 global shared lock. We do this my calling code outside of MDL.
425 */
conflicting_locksMDL_lock::MDL_scoped_lock426 virtual bool conflicting_locks(const MDL_ticket *ticket) const
427 { return ticket->get_type() == MDL_INTENTION_EXCLUSIVE; }
428
429 /*
430 In scoped locks, only IX lock request would starve because of X/S. But that
431 is practically very rare case. So just return 0 from this function.
432 */
hog_lock_types_bitmapMDL_lock::MDL_scoped_lock433 virtual bitmap_t hog_lock_types_bitmap() const
434 { return 0; }
435 private:
436 static const bitmap_t m_granted_incompatible[MDL_TYPE_END];
437 static const bitmap_t m_waiting_incompatible[MDL_TYPE_END];
438 };
439
440
441 /**
442 An implementation of a per-object lock. Supports SHARED, SHARED_UPGRADABLE,
443 SHARED HIGH PRIORITY and EXCLUSIVE locks.
444 */
445 struct MDL_object_lock : public MDL_lock_strategy
446 {
MDL_object_lockMDL_lock::MDL_object_lock447 MDL_object_lock() {}
incompatible_granted_types_bitmapMDL_lock::MDL_object_lock448 virtual const bitmap_t *incompatible_granted_types_bitmap() const
449 { return m_granted_incompatible; }
incompatible_waiting_types_bitmapMDL_lock::MDL_object_lock450 virtual const bitmap_t *incompatible_waiting_types_bitmap() const
451 { return m_waiting_incompatible; }
needs_notificationMDL_lock::MDL_object_lock452 virtual bool needs_notification(const MDL_ticket *ticket) const
453 {
454 return (MDL_BIT(ticket->get_type()) &
455 (MDL_BIT(MDL_SHARED_NO_WRITE) |
456 MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
457 MDL_BIT(MDL_EXCLUSIVE)));
458 }
459
460 /**
461 Notify threads holding a shared metadata locks on object which
462 conflict with a pending X, SNW or SNRW lock.
463
464 If thread which holds conflicting lock is waiting on table-level
465 lock or some other non-MDL resource we might need to wake it up
466 by calling code outside of MDL.
467 */
conflicting_locksMDL_lock::MDL_object_lock468 virtual bool conflicting_locks(const MDL_ticket *ticket) const
469 { return ticket->get_type() < MDL_SHARED_UPGRADABLE; }
470
471 /*
472 To prevent starvation, these lock types that are only granted
473 max_write_lock_count times in a row while other lock types are
474 waiting.
475 */
hog_lock_types_bitmapMDL_lock::MDL_object_lock476 virtual bitmap_t hog_lock_types_bitmap() const
477 {
478 return (MDL_BIT(MDL_SHARED_NO_WRITE) |
479 MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
480 MDL_BIT(MDL_EXCLUSIVE));
481 }
482
483 private:
484 static const bitmap_t m_granted_incompatible[MDL_TYPE_END];
485 static const bitmap_t m_waiting_incompatible[MDL_TYPE_END];
486 };
487
488
489 struct MDL_backup_lock: public MDL_lock_strategy
490 {
MDL_backup_lockMDL_lock::MDL_backup_lock491 MDL_backup_lock() {}
incompatible_granted_types_bitmapMDL_lock::MDL_backup_lock492 virtual const bitmap_t *incompatible_granted_types_bitmap() const
493 { return m_granted_incompatible; }
incompatible_waiting_types_bitmapMDL_lock::MDL_backup_lock494 virtual const bitmap_t *incompatible_waiting_types_bitmap() const
495 { return m_waiting_incompatible; }
needs_notificationMDL_lock::MDL_backup_lock496 virtual bool needs_notification(const MDL_ticket *ticket) const
497 {
498 return (MDL_BIT(ticket->get_type()) & MDL_BIT(MDL_BACKUP_FTWRL1));
499 }
500
501 /**
502 Insert delayed threads may hold DML or TRANS_DML lock.
503 We need to kill such threads in order to get lock for FTWRL statements.
504 We do this by calling code outside of MDL.
505 */
conflicting_locksMDL_lock::MDL_backup_lock506 virtual bool conflicting_locks(const MDL_ticket *ticket) const
507 {
508 return (MDL_BIT(ticket->get_type()) &
509 (MDL_BIT(MDL_BACKUP_DML) |
510 MDL_BIT(MDL_BACKUP_TRANS_DML)));
511 }
512
513 /*
514 In backup namespace DML/DDL may starve because of concurrent FTWRL or
515 BACKUP statements. This scenario is partically useless in real world,
516 so we just return 0 here.
517 */
hog_lock_types_bitmapMDL_lock::MDL_backup_lock518 virtual bitmap_t hog_lock_types_bitmap() const
519 { return 0; }
520 private:
521 static const bitmap_t m_granted_incompatible[MDL_BACKUP_END];
522 static const bitmap_t m_waiting_incompatible[MDL_BACKUP_END];
523 };
524
525 public:
526 /** The key of the object (data) being protected. */
527 MDL_key key;
528 /**
529 Read-write lock protecting this lock context.
530
531 @note The fact that we use read-write lock prefers readers here is
532 important as deadlock detector won't work correctly otherwise.
533
534 For example, imagine that we have following waiters graph:
535
536 ctxA -> obj1 -> ctxB -> obj1 -|
537 ^ |
538 |----------------------------|
539
540 and both ctxA and ctxB start deadlock detection process:
541
542 ctxA read-locks obj1 ctxB read-locks obj2
543 ctxA goes deeper ctxB goes deeper
544
545 Now ctxC comes in who wants to start waiting on obj1, also
546 ctxD comes in who wants to start waiting on obj2.
547
548 ctxC tries to write-lock obj1 ctxD tries to write-lock obj2
549 ctxC is blocked ctxD is blocked
550
551 Now ctxA and ctxB resume their search:
552
553 ctxA tries to read-lock obj2 ctxB tries to read-lock obj1
554
555 If m_rwlock prefers writes (or fair) both ctxA and ctxB would be
556 blocked because of pending write locks from ctxD and ctxC
557 correspondingly. Thus we will get a deadlock in deadlock detector.
558 If m_wrlock prefers readers (actually ignoring pending writers is
559 enough) ctxA and ctxB will continue and no deadlock will occur.
560 */
561 mysql_prlock_t m_rwlock;
562
is_empty() const563 bool is_empty() const
564 {
565 return (m_granted.is_empty() && m_waiting.is_empty());
566 }
567
incompatible_granted_types_bitmap() const568 const bitmap_t *incompatible_granted_types_bitmap() const
569 { return m_strategy->incompatible_granted_types_bitmap(); }
incompatible_waiting_types_bitmap() const570 const bitmap_t *incompatible_waiting_types_bitmap() const
571 { return m_strategy->incompatible_waiting_types_bitmap(); }
572
573 bool has_pending_conflicting_lock(enum_mdl_type type);
574
575 bool can_grant_lock(enum_mdl_type type, MDL_context *requstor_ctx,
576 bool ignore_lock_priority) const;
577
578 inline unsigned long get_lock_owner() const;
579
580 void reschedule_waiters();
581
582 void remove_ticket(LF_PINS *pins, Ticket_list MDL_lock::*queue,
583 MDL_ticket *ticket);
584
585 bool visit_subgraph(MDL_ticket *waiting_ticket,
586 MDL_wait_for_graph_visitor *gvisitor);
587
needs_notification(const MDL_ticket * ticket) const588 bool needs_notification(const MDL_ticket *ticket) const
589 { return m_strategy->needs_notification(ticket); }
notify_conflicting_locks(MDL_context * ctx)590 void notify_conflicting_locks(MDL_context *ctx)
591 {
592 Ticket_iterator it(m_granted);
593 MDL_ticket *conflicting_ticket;
594 while ((conflicting_ticket= it++))
595 {
596 if (conflicting_ticket->get_ctx() != ctx &&
597 m_strategy->conflicting_locks(conflicting_ticket))
598 {
599 MDL_context *conflicting_ctx= conflicting_ticket->get_ctx();
600
601 ctx->get_owner()->
602 notify_shared_lock(conflicting_ctx->get_owner(),
603 conflicting_ctx->get_needs_thr_lock_abort());
604 }
605 }
606 }
607
hog_lock_types_bitmap() const608 bitmap_t hog_lock_types_bitmap() const
609 { return m_strategy->hog_lock_types_bitmap(); }
610
611 #ifndef DBUG_OFF
612 bool check_if_conflicting_replication_locks(MDL_context *ctx);
613 #endif
614
615 /** List of granted tickets for this lock. */
616 Ticket_list m_granted;
617 /** Tickets for contexts waiting to acquire a lock. */
618 Ticket_list m_waiting;
619
620 /**
621 Number of times high priority lock requests have been granted while
622 low priority lock requests were waiting.
623 */
624 ulong m_hog_lock_count;
625
626 public:
627
MDL_lock()628 MDL_lock()
629 : m_hog_lock_count(0),
630 m_strategy(0)
631 { mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock); }
632
MDL_lock(const MDL_key * key_arg)633 MDL_lock(const MDL_key *key_arg)
634 : key(key_arg),
635 m_hog_lock_count(0),
636 m_strategy(&m_backup_lock_strategy)
637 {
638 DBUG_ASSERT(key_arg->mdl_namespace() == MDL_key::BACKUP);
639 mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock);
640 }
641
~MDL_lock()642 ~MDL_lock()
643 { mysql_prlock_destroy(&m_rwlock); }
644
lf_alloc_constructor(uchar * arg)645 static void lf_alloc_constructor(uchar *arg)
646 { new (arg + LF_HASH_OVERHEAD) MDL_lock(); }
647
lf_alloc_destructor(uchar * arg)648 static void lf_alloc_destructor(uchar *arg)
649 { ((MDL_lock*)(arg + LF_HASH_OVERHEAD))->~MDL_lock(); }
650
lf_hash_initializer(LF_HASH * hash,MDL_lock * lock,MDL_key * key_arg)651 static void lf_hash_initializer(LF_HASH *hash __attribute__((unused)),
652 MDL_lock *lock, MDL_key *key_arg)
653 {
654 DBUG_ASSERT(key_arg->mdl_namespace() != MDL_key::BACKUP);
655 new (&lock->key) MDL_key(key_arg);
656 if (key_arg->mdl_namespace() == MDL_key::SCHEMA)
657 lock->m_strategy= &m_scoped_lock_strategy;
658 else
659 lock->m_strategy= &m_object_lock_strategy;
660 }
661
662 const MDL_lock_strategy *m_strategy;
663 private:
664 static const MDL_backup_lock m_backup_lock_strategy;
665 static const MDL_scoped_lock m_scoped_lock_strategy;
666 static const MDL_object_lock m_object_lock_strategy;
667 };
668
669
670 const MDL_lock::MDL_backup_lock MDL_lock::m_backup_lock_strategy;
671 const MDL_lock::MDL_scoped_lock MDL_lock::m_scoped_lock_strategy;
672 const MDL_lock::MDL_object_lock MDL_lock::m_object_lock_strategy;
673
674
675 static MDL_map mdl_locks;
676
677
678 extern "C"
679 {
680 static uchar *
mdl_locks_key(const uchar * record,size_t * length,my_bool not_used)681 mdl_locks_key(const uchar *record, size_t *length,
682 my_bool not_used __attribute__((unused)))
683 {
684 MDL_lock *lock=(MDL_lock*) record;
685 *length= lock->key.length();
686 return (uchar*) lock->key.ptr();
687 }
688 } /* extern "C" */
689
690
691 /**
692 Initialize the metadata locking subsystem.
693
694 This function is called at server startup.
695
696 In particular, initializes the new global mutex and
697 the associated condition variable: LOCK_mdl and COND_mdl.
698 These locking primitives are implementation details of the MDL
699 subsystem and are private to it.
700 */
701
mdl_init()702 void mdl_init()
703 {
704 DBUG_ASSERT(! mdl_initialized);
705 mdl_initialized= TRUE;
706
707 #ifdef HAVE_PSI_INTERFACE
708 init_mdl_psi_keys();
709 #endif
710
711 mdl_locks.init();
712 }
713
714
715 /**
716 Release resources of metadata locking subsystem.
717
718 Destroys the global mutex and the condition variable.
719 Called at server shutdown.
720 */
721
mdl_destroy()722 void mdl_destroy()
723 {
724 if (mdl_initialized)
725 {
726 mdl_initialized= FALSE;
727 mdl_locks.destroy();
728 }
729 }
730
731
732 struct mdl_iterate_arg
733 {
734 mdl_iterator_callback callback;
735 void *argument;
736 };
737
738
mdl_iterate_lock(MDL_lock * lock,mdl_iterate_arg * arg)739 static my_bool mdl_iterate_lock(MDL_lock *lock, mdl_iterate_arg *arg)
740 {
741 int res= FALSE;
742 /*
743 We can skip check for m_strategy here, becase m_granted
744 must be empty for such locks anyway.
745 */
746 mysql_prlock_rdlock(&lock->m_rwlock);
747 MDL_lock::Ticket_iterator granted_it(lock->m_granted);
748 MDL_lock::Ticket_iterator waiting_it(lock->m_waiting);
749 MDL_ticket *ticket;
750 while ((ticket= granted_it++) && !(res= arg->callback(ticket, arg->argument, true)))
751 /* no-op */;
752 while ((ticket= waiting_it++) && !(res= arg->callback(ticket, arg->argument, false)))
753 /* no-op */;
754 mysql_prlock_unlock(&lock->m_rwlock);
755 return MY_TEST(res);
756 }
757
758
mdl_iterate(mdl_iterator_callback callback,void * arg)759 int mdl_iterate(mdl_iterator_callback callback, void *arg)
760 {
761 DBUG_ENTER("mdl_iterate");
762 mdl_iterate_arg argument= { callback, arg };
763 LF_PINS *pins= mdl_locks.get_pins();
764 int res= 1;
765
766 if (pins)
767 {
768 res= mdl_iterate_lock(mdl_locks.m_backup_lock, &argument) ||
769 lf_hash_iterate(&mdl_locks.m_locks, pins,
770 (my_hash_walk_action) mdl_iterate_lock, &argument);
771 lf_hash_put_pins(pins);
772 }
773 DBUG_RETURN(res);
774 }
775
776
mdl_hash_function(CHARSET_INFO * cs,const uchar * key,size_t length)777 my_hash_value_type mdl_hash_function(CHARSET_INFO *cs,
778 const uchar *key, size_t length)
779 {
780 MDL_key *mdl_key= (MDL_key*) (key - offsetof(MDL_key, m_ptr));
781 return mdl_key->hash_value();
782 }
783
784
785 /** Initialize the container for all MDL locks. */
786
init()787 void MDL_map::init()
788 {
789 MDL_key backup_lock_key(MDL_key::BACKUP, "", "");
790
791 m_backup_lock= new (std::nothrow) MDL_lock(&backup_lock_key);
792
793 lf_hash_init(&m_locks, sizeof(MDL_lock), LF_HASH_UNIQUE, 0, 0,
794 mdl_locks_key, &my_charset_bin);
795 m_locks.alloc.constructor= MDL_lock::lf_alloc_constructor;
796 m_locks.alloc.destructor= MDL_lock::lf_alloc_destructor;
797 m_locks.initializer= (lf_hash_initializer) MDL_lock::lf_hash_initializer;
798 m_locks.hash_function= mdl_hash_function;
799 }
800
801
802 /**
803 Destroy the container for all MDL locks.
804 @pre It must be empty.
805 */
806
destroy()807 void MDL_map::destroy()
808 {
809 delete m_backup_lock;
810
811 DBUG_ASSERT(!lf_hash_size(&m_locks));
812 lf_hash_destroy(&m_locks);
813 }
814
815
816 /**
817 Find MDL_lock object corresponding to the key, create it
818 if it does not exist.
819
820 @retval non-NULL - Success. MDL_lock instance for the key with
821 locked MDL_lock::m_rwlock.
822 @retval NULL - Failure (OOM).
823 */
824
find_or_insert(LF_PINS * pins,const MDL_key * mdl_key)825 MDL_lock* MDL_map::find_or_insert(LF_PINS *pins, const MDL_key *mdl_key)
826 {
827 MDL_lock *lock;
828
829 if (mdl_key->mdl_namespace() == MDL_key::BACKUP)
830 {
831 /*
832 Return pointer to pre-allocated MDL_lock instance. Such an optimization
833 allows to save one hash lookup for any statement changing data.
834
835 It works since this namespace contains only one element so keys
836 for them look like '<namespace-id>\0\0'.
837 */
838 DBUG_ASSERT(mdl_key->length() == 3);
839 mysql_prlock_wrlock(&m_backup_lock->m_rwlock);
840 return m_backup_lock;
841 }
842
843 retry:
844 while (!(lock= (MDL_lock*) lf_hash_search(&m_locks, pins, mdl_key->ptr(),
845 mdl_key->length())))
846 if (lf_hash_insert(&m_locks, pins, (uchar*) mdl_key) == -1)
847 return NULL;
848
849 mysql_prlock_wrlock(&lock->m_rwlock);
850 if (unlikely(!lock->m_strategy))
851 {
852 mysql_prlock_unlock(&lock->m_rwlock);
853 lf_hash_search_unpin(pins);
854 goto retry;
855 }
856 lf_hash_search_unpin(pins);
857
858 return lock;
859 }
860
861
862 /**
863 * Return thread id of the owner of the lock, if it is owned.
864 */
865
866 unsigned long
get_lock_owner(LF_PINS * pins,const MDL_key * mdl_key)867 MDL_map::get_lock_owner(LF_PINS *pins, const MDL_key *mdl_key)
868 {
869 unsigned long res= 0;
870
871 if (mdl_key->mdl_namespace() == MDL_key::BACKUP)
872 {
873 mysql_prlock_rdlock(&m_backup_lock->m_rwlock);
874 res= m_backup_lock->get_lock_owner();
875 mysql_prlock_unlock(&m_backup_lock->m_rwlock);
876 }
877 else
878 {
879 MDL_lock *lock= (MDL_lock*) lf_hash_search(&m_locks, pins, mdl_key->ptr(),
880 mdl_key->length());
881 if (lock)
882 {
883 /*
884 We can skip check for m_strategy here, becase m_granted
885 must be empty for such locks anyway.
886 */
887 mysql_prlock_rdlock(&lock->m_rwlock);
888 res= lock->get_lock_owner();
889 mysql_prlock_unlock(&lock->m_rwlock);
890 lf_hash_search_unpin(pins);
891 }
892 }
893 return res;
894 }
895
896
897 /**
898 Destroy MDL_lock object or delegate this responsibility to
899 whatever thread that holds the last outstanding reference to
900 it.
901 */
902
remove(LF_PINS * pins,MDL_lock * lock)903 void MDL_map::remove(LF_PINS *pins, MDL_lock *lock)
904 {
905 if (lock->key.mdl_namespace() == MDL_key::BACKUP)
906 {
907 /* Never destroy pre-allocated MDL_lock object in BACKUP namespace. */
908 mysql_prlock_unlock(&lock->m_rwlock);
909 return;
910 }
911
912 lock->m_strategy= 0;
913 mysql_prlock_unlock(&lock->m_rwlock);
914 lf_hash_delete(&m_locks, pins, lock->key.ptr(), lock->key.length());
915 }
916
917
918 /**
919 Initialize a metadata locking context.
920
921 This is to be called when a new server connection is created.
922 */
923
MDL_context()924 MDL_context::MDL_context()
925 :
926 m_owner(NULL),
927 m_needs_thr_lock_abort(FALSE),
928 m_waiting_for(NULL),
929 m_pins(NULL)
930 {
931 mysql_prlock_init(key_MDL_context_LOCK_waiting_for, &m_LOCK_waiting_for);
932 }
933
934
935 /**
936 Destroy metadata locking context.
937
938 Assumes and asserts that there are no active or pending locks
939 associated with this context at the time of the destruction.
940
941 Currently does nothing. Asserts that there are no pending
942 or satisfied lock requests. The pending locks must be released
943 prior to destruction. This is a new way to express the assertion
944 that all tables are closed before a connection is destroyed.
945 */
946
destroy()947 void MDL_context::destroy()
948 {
949 DBUG_ASSERT(m_tickets[MDL_STATEMENT].is_empty());
950 DBUG_ASSERT(m_tickets[MDL_TRANSACTION].is_empty());
951 DBUG_ASSERT(m_tickets[MDL_EXPLICIT].is_empty());
952
953 mysql_prlock_destroy(&m_LOCK_waiting_for);
954 if (m_pins)
955 lf_hash_put_pins(m_pins);
956 }
957
958
fix_pins()959 bool MDL_context::fix_pins()
960 {
961 return m_pins ? false : (m_pins= mdl_locks.get_pins()) == 0;
962 }
963
964
965 /**
966 Initialize a lock request.
967
968 This is to be used for every lock request.
969
970 Note that initialization and allocation are split into two
971 calls. This is to allow flexible memory management of lock
972 requests. Normally a lock request is stored in statement memory
973 (e.g. is a member of struct TABLE_LIST), but we would also like
974 to allow allocation of lock requests in other memory roots,
975 for example in the grant subsystem, to lock privilege tables.
976
977 The MDL subsystem does not own or manage memory of lock requests.
978
979 @param mdl_namespace Id of namespace of object to be locked
980 @param db Name of database to which the object belongs
981 @param name Name of of the object
982 @param mdl_type The MDL lock type for the request.
983 */
984
init(MDL_key::enum_mdl_namespace mdl_namespace,const char * db_arg,const char * name_arg,enum_mdl_type mdl_type_arg,enum_mdl_duration mdl_duration_arg)985 void MDL_request::init(MDL_key::enum_mdl_namespace mdl_namespace,
986 const char *db_arg,
987 const char *name_arg,
988 enum_mdl_type mdl_type_arg,
989 enum_mdl_duration mdl_duration_arg)
990 {
991 key.mdl_key_init(mdl_namespace, db_arg, name_arg);
992 type= mdl_type_arg;
993 duration= mdl_duration_arg;
994 ticket= NULL;
995 }
996
997
998 /**
999 Initialize a lock request using pre-built MDL_key.
1000
1001 @sa MDL_request::init(namespace, db, name, type).
1002
1003 @param key_arg The pre-built MDL key for the request.
1004 @param mdl_type_arg The MDL lock type for the request.
1005 */
1006
init(const MDL_key * key_arg,enum_mdl_type mdl_type_arg,enum_mdl_duration mdl_duration_arg)1007 void MDL_request::init(const MDL_key *key_arg,
1008 enum_mdl_type mdl_type_arg,
1009 enum_mdl_duration mdl_duration_arg)
1010 {
1011 key.mdl_key_init(key_arg);
1012 type= mdl_type_arg;
1013 duration= mdl_duration_arg;
1014 ticket= NULL;
1015 }
1016
1017
1018 /**
1019 Auxiliary functions needed for creation/destruction of MDL_ticket
1020 objects.
1021
1022 @todo This naive implementation should be replaced with one that saves
1023 on memory allocation by reusing released objects.
1024 */
1025
create(MDL_context * ctx_arg,enum_mdl_type type_arg,enum_mdl_duration duration_arg)1026 MDL_ticket *MDL_ticket::create(MDL_context *ctx_arg, enum_mdl_type type_arg
1027 #ifndef DBUG_OFF
1028 , enum_mdl_duration duration_arg
1029 #endif
1030 )
1031 {
1032 return new (std::nothrow)
1033 MDL_ticket(ctx_arg, type_arg
1034 #ifndef DBUG_OFF
1035 , duration_arg
1036 #endif
1037 );
1038 }
1039
1040
destroy(MDL_ticket * ticket)1041 void MDL_ticket::destroy(MDL_ticket *ticket)
1042 {
1043 delete ticket;
1044 }
1045
1046
1047 /**
1048 Return the 'weight' of this ticket for the
1049 victim selection algorithm. Requests with
1050 lower weight are preferred to requests
1051 with higher weight when choosing a victim.
1052 */
1053
get_deadlock_weight() const1054 uint MDL_ticket::get_deadlock_weight() const
1055 {
1056 if (m_lock->key.mdl_namespace() == MDL_key::BACKUP)
1057 {
1058 if (m_type == MDL_BACKUP_FTWRL1)
1059 return DEADLOCK_WEIGHT_FTWRL1;
1060 return DEADLOCK_WEIGHT_DDL;
1061 }
1062 return m_type >= MDL_SHARED_UPGRADABLE ?
1063 DEADLOCK_WEIGHT_DDL : DEADLOCK_WEIGHT_DML;
1064 }
1065
1066
1067 /** Construct an empty wait slot. */
1068
MDL_wait()1069 MDL_wait::MDL_wait()
1070 :m_wait_status(EMPTY)
1071 {
1072 mysql_mutex_init(key_MDL_wait_LOCK_wait_status, &m_LOCK_wait_status, NULL);
1073 mysql_cond_init(key_MDL_wait_COND_wait_status, &m_COND_wait_status, NULL);
1074 }
1075
1076
1077 /** Destroy system resources. */
1078
~MDL_wait()1079 MDL_wait::~MDL_wait()
1080 {
1081 mysql_mutex_destroy(&m_LOCK_wait_status);
1082 mysql_cond_destroy(&m_COND_wait_status);
1083 }
1084
1085
1086 /**
1087 Set the status unless it's already set. Return FALSE if set,
1088 TRUE otherwise.
1089 */
1090
set_status(enum_wait_status status_arg)1091 bool MDL_wait::set_status(enum_wait_status status_arg)
1092 {
1093 bool was_occupied= TRUE;
1094 mysql_mutex_lock(&m_LOCK_wait_status);
1095 if (m_wait_status == EMPTY)
1096 {
1097 was_occupied= FALSE;
1098 m_wait_status= status_arg;
1099 mysql_cond_signal(&m_COND_wait_status);
1100 }
1101 mysql_mutex_unlock(&m_LOCK_wait_status);
1102 return was_occupied;
1103 }
1104
1105
1106 /** Query the current value of the wait slot. */
1107
get_status()1108 MDL_wait::enum_wait_status MDL_wait::get_status()
1109 {
1110 enum_wait_status result;
1111 mysql_mutex_lock(&m_LOCK_wait_status);
1112 result= m_wait_status;
1113 mysql_mutex_unlock(&m_LOCK_wait_status);
1114 return result;
1115 }
1116
1117
1118 /** Clear the current value of the wait slot. */
1119
reset_status()1120 void MDL_wait::reset_status()
1121 {
1122 mysql_mutex_lock(&m_LOCK_wait_status);
1123 m_wait_status= EMPTY;
1124 mysql_mutex_unlock(&m_LOCK_wait_status);
1125 }
1126
1127
1128 /**
1129 Wait for the status to be assigned to this wait slot.
1130
1131 @param owner MDL context owner.
1132 @param abs_timeout Absolute time after which waiting should stop.
1133 @param set_status_on_timeout TRUE - If in case of timeout waiting
1134 context should close the wait slot by
1135 sending TIMEOUT to itself.
1136 FALSE - Otherwise.
1137 @param wait_state_name Thread state name to be set for duration of wait.
1138
1139 @returns Signal posted.
1140 */
1141
1142 MDL_wait::enum_wait_status
timed_wait(MDL_context_owner * owner,struct timespec * abs_timeout,bool set_status_on_timeout,const PSI_stage_info * wait_state_name)1143 MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
1144 bool set_status_on_timeout,
1145 const PSI_stage_info *wait_state_name)
1146 {
1147 PSI_stage_info old_stage;
1148 enum_wait_status result;
1149 int wait_result= 0;
1150 DBUG_ENTER("MDL_wait::timed_wait");
1151
1152 mysql_mutex_lock(&m_LOCK_wait_status);
1153
1154 owner->ENTER_COND(&m_COND_wait_status, &m_LOCK_wait_status,
1155 wait_state_name, & old_stage);
1156 thd_wait_begin(NULL, THD_WAIT_META_DATA_LOCK);
1157 while (!m_wait_status && !owner->is_killed() &&
1158 wait_result != ETIMEDOUT && wait_result != ETIME)
1159 {
1160 #ifdef WITH_WSREP
1161 // Allow tests to block the applier thread using the DBUG facilities
1162 DBUG_EXECUTE_IF("sync.wsrep_before_mdl_wait",
1163 {
1164 const char act[]=
1165 "now "
1166 "wait_for signal.wsrep_before_mdl_wait";
1167 DBUG_ASSERT(!debug_sync_set_action((owner->get_thd()),
1168 STRING_WITH_LEN(act)));
1169 };);
1170 if (WSREP_ON && wsrep_thd_is_BF(owner->get_thd(), false))
1171 {
1172 wait_result= mysql_cond_wait(&m_COND_wait_status, &m_LOCK_wait_status);
1173 }
1174 else
1175 #endif /* WITH_WSREP */
1176 wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
1177 abs_timeout);
1178 }
1179 thd_wait_end(NULL);
1180
1181 if (m_wait_status == EMPTY)
1182 {
1183 /*
1184 Wait has ended not due to a status being set from another
1185 thread but due to this connection/statement being killed or a
1186 time out.
1187 To avoid races, which may occur if another thread sets
1188 GRANTED status before the code which calls this method
1189 processes the abort/timeout, we assign the status under
1190 protection of the m_LOCK_wait_status, within the critical
1191 section. An exception is when set_status_on_timeout is
1192 false, which means that the caller intends to restart the
1193 wait.
1194 */
1195 if (owner->is_killed())
1196 m_wait_status= KILLED;
1197 else if (set_status_on_timeout)
1198 m_wait_status= TIMEOUT;
1199 }
1200 result= m_wait_status;
1201
1202 owner->EXIT_COND(& old_stage);
1203
1204 DBUG_RETURN(result);
1205 }
1206
1207
1208 /**
1209 Clear bit corresponding to the type of metadata lock in bitmap representing
1210 set of such types if list of tickets does not contain ticket with such type.
1211
1212 @param[in,out] bitmap Bitmap representing set of types of locks.
1213 @param[in] list List to inspect.
1214 @param[in] type Type of metadata lock to look up in the list.
1215 */
1216
clear_bit_if_not_in_list(enum_mdl_type type)1217 void MDL_lock::Ticket_list::clear_bit_if_not_in_list(enum_mdl_type type)
1218 {
1219 MDL_lock::Ticket_iterator it(m_list);
1220 const MDL_ticket *ticket;
1221
1222 while ((ticket= it++))
1223 if (ticket->get_type() == type)
1224 return;
1225 m_bitmap&= ~ MDL_BIT(type);
1226 }
1227
1228
1229 /**
1230 Add ticket to MDL_lock's list of waiting requests and
1231 update corresponding bitmap of lock types.
1232 */
1233
add_ticket(MDL_ticket * ticket)1234 void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket)
1235 {
1236 /*
1237 Ticket being added to the list must have MDL_ticket::m_lock set,
1238 since for such tickets methods accessing this member might be
1239 called by other threads.
1240 */
1241 DBUG_ASSERT(ticket->get_lock());
1242 #ifdef WITH_WSREP
1243 if (WSREP_ON && (this == &(ticket->get_lock()->m_waiting)) &&
1244 wsrep_thd_is_BF(ticket->get_ctx()->get_thd(), false))
1245 {
1246 Ticket_iterator itw(ticket->get_lock()->m_waiting);
1247 MDL_ticket *waiting;
1248 MDL_ticket *prev=NULL;
1249 bool added= false;
1250
1251 DBUG_ASSERT(WSREP(ticket->get_ctx()->get_thd()));
1252
1253 while ((waiting= itw++) && !added)
1254 {
1255 if (!wsrep_thd_is_BF(waiting->get_ctx()->get_thd(), true))
1256 {
1257 WSREP_DEBUG("MDL add_ticket inserted before: %lu %s",
1258 thd_get_thread_id(waiting->get_ctx()->get_thd()),
1259 wsrep_thd_query(waiting->get_ctx()->get_thd()));
1260 /* Insert the ticket before the first non-BF waiting thd. */
1261 m_list.insert_after(prev, ticket);
1262 added= true;
1263 }
1264 prev= waiting;
1265 }
1266
1267 /* Otherwise, insert the ticket at the back of the waiting list. */
1268 if (!added)
1269 m_list.push_back(ticket);
1270 }
1271 else
1272 #endif /* WITH_WSREP */
1273 {
1274 /*
1275 Add ticket to the *back* of the queue to ensure fairness
1276 among requests with the same priority.
1277 */
1278 m_list.push_back(ticket);
1279 }
1280 m_bitmap|= MDL_BIT(ticket->get_type());
1281 }
1282
1283
1284 /**
1285 Remove ticket from MDL_lock's list of requests and
1286 update corresponding bitmap of lock types.
1287 */
1288
remove_ticket(MDL_ticket * ticket)1289 void MDL_lock::Ticket_list::remove_ticket(MDL_ticket *ticket)
1290 {
1291 m_list.remove(ticket);
1292 /*
1293 Check if waiting queue has another ticket with the same type as
1294 one which was removed. If there is no such ticket, i.e. we have
1295 removed last ticket of particular type, then we need to update
1296 bitmap of waiting ticket's types.
1297 Note that in most common case, i.e. when shared lock is removed
1298 from waiting queue, we are likely to find ticket of the same
1299 type early without performing full iteration through the list.
1300 So this method should not be too expensive.
1301 */
1302 clear_bit_if_not_in_list(ticket->get_type());
1303 }
1304
1305
1306 /**
1307 Determine waiting contexts which requests for the lock can be
1308 satisfied, grant lock to them and wake them up.
1309
1310 @note Together with MDL_lock::add_ticket() this method implements
1311 fair scheduling among requests with the same priority.
1312 It tries to grant lock from the head of waiters list, while
1313 add_ticket() adds new requests to the back of this list.
1314
1315 */
1316
reschedule_waiters()1317 void MDL_lock::reschedule_waiters()
1318 {
1319 MDL_lock::Ticket_iterator it(m_waiting);
1320 MDL_ticket *ticket;
1321 bool skip_high_priority= false;
1322 bitmap_t hog_lock_types= hog_lock_types_bitmap();
1323
1324 if (m_hog_lock_count >= max_write_lock_count)
1325 {
1326 /*
1327 If number of successively granted high-prio, strong locks has exceeded
1328 max_write_lock_count give a way to low-prio, weak locks to avoid their
1329 starvation.
1330 */
1331
1332 if ((m_waiting.bitmap() & ~hog_lock_types) != 0)
1333 {
1334 /*
1335 Even though normally when m_hog_lock_count is non-0 there is
1336 some pending low-prio lock, we still can encounter situation
1337 when m_hog_lock_count is non-0 and there are no pending low-prio
1338 locks. This, for example, can happen when a ticket for pending
1339 low-prio lock was removed from waiters list due to timeout,
1340 and reschedule_waiters() is called after that to update the
1341 waiters queue. m_hog_lock_count will be reset to 0 at the
1342 end of this call in such case.
1343
1344 Note that it is not an issue if we fail to wake up any pending
1345 waiters for weak locks in the loop below. This would mean that
1346 all of them are either killed, timed out or chosen as a victim
1347 by deadlock resolver, but have not managed to remove ticket
1348 from the waiters list yet. After tickets will be removed from
1349 the waiters queue there will be another call to
1350 reschedule_waiters() with pending bitmap updated to reflect new
1351 state of waiters queue.
1352 */
1353 skip_high_priority= true;
1354 }
1355 }
1356
1357 /*
1358 Find the first (and hence the oldest) waiting request which
1359 can be satisfied (taking into account priority). Grant lock to it.
1360 Repeat the process for the remainder of waiters.
1361 Note we don't need to re-start iteration from the head of the
1362 list after satisfying the first suitable request as in our case
1363 all compatible types of requests have the same priority.
1364
1365 TODO/FIXME: We should:
1366 - Either switch to scheduling without priorities
1367 which will allow to stop iteration through the
1368 list of waiters once we found the first ticket
1369 which can't be satisfied
1370 - Or implement some check using bitmaps which will
1371 allow to stop iteration in cases when, e.g., we
1372 grant SNRW lock and there are no pending S or
1373 SH locks.
1374 */
1375 while ((ticket= it++))
1376 {
1377 /*
1378 Skip high-prio, strong locks if earlier we have decided to give way to
1379 low-prio, weaker locks.
1380 */
1381 if (skip_high_priority &&
1382 ((MDL_BIT(ticket->get_type()) & hog_lock_types) != 0))
1383 continue;
1384
1385 if (can_grant_lock(ticket->get_type(), ticket->get_ctx(),
1386 skip_high_priority))
1387 {
1388 if (! ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED))
1389 {
1390 /*
1391 Satisfy the found request by updating lock structures.
1392 It is OK to do so even after waking up the waiter since any
1393 session which tries to get any information about the state of
1394 this lock has to acquire MDL_lock::m_rwlock first and thus,
1395 when manages to do so, already sees an updated state of the
1396 MDL_lock object.
1397 */
1398 m_waiting.remove_ticket(ticket);
1399 m_granted.add_ticket(ticket);
1400
1401 /*
1402 Increase counter of successively granted high-priority strong locks,
1403 if we have granted one.
1404 */
1405 if ((MDL_BIT(ticket->get_type()) & hog_lock_types) != 0)
1406 m_hog_lock_count++;
1407 }
1408 /*
1409 If we could not update the wait slot of the waiter,
1410 it can be due to fact that its connection/statement was
1411 killed or it has timed out (i.e. the slot is not empty).
1412 Since in all such cases the waiter assumes that the lock was
1413 not been granted, we should keep the request in the waiting
1414 queue and look for another request to reschedule.
1415 */
1416 }
1417 }
1418
1419 if ((m_waiting.bitmap() & ~hog_lock_types) == 0)
1420 {
1421 /*
1422 Reset number of successively granted high-prio, strong locks
1423 if there are no pending low-prio, weak locks.
1424 This ensures:
1425 - That m_hog_lock_count is correctly reset after strong lock
1426 is released and weak locks are granted (or there are no
1427 other lock requests).
1428 - That situation when SNW lock is granted along with some SR
1429 locks, but SW locks are still blocked are handled correctly.
1430 - That m_hog_lock_count is zero in most cases when there are no pending
1431 weak locks (see comment at the start of this method for example of
1432 exception). This allows to save on checks at the start of this method.
1433 */
1434 m_hog_lock_count= 0;
1435 }
1436 }
1437
1438
1439 /**
1440 Compatibility (or rather "incompatibility") matrices for scoped metadata
1441 lock.
1442 Scoped locks are database (or schema) locks.
1443 Arrays of bitmaps which elements specify which granted/waiting locks
1444 are incompatible with type of lock being requested.
1445
1446 The first array specifies if particular type of request can be satisfied
1447 if there is granted scoped lock of certain type.
1448
1449 (*) Since intention shared scoped locks (IS) are compatible with all other
1450 type of locks, they don't need to be implemented and there is no code
1451 for them.
1452
1453 | Type of active |
1454 Request | scoped lock |
1455 type | IS(*) IX S X |
1456 ---------+------------------+
1457 IS(*) | + + + + |
1458 IX | + + - - |
1459 S | + - + - |
1460 X | + - - - |
1461
1462 The second array specifies if particular type of request can be satisfied
1463 if there is already waiting request for the scoped lock of certain type.
1464 I.e. it specifies what is the priority of different lock types.
1465
1466 | Pending |
1467 Request | scoped lock |
1468 type | IS(*) IX S X |
1469 ---------+-----------------+
1470 IS(*) | + + + + |
1471 IX | + + - - |
1472 S | + + + - |
1473 X | + + + + |
1474
1475 Here: "+" -- means that request can be satisfied
1476 "-" -- means that request can't be satisfied and should wait
1477
1478 Note that relation between scoped locks and objects locks requested
1479 by statement is not straightforward and is therefore fully defined
1480 by SQL-layer.
1481 For example, in order to support global read lock implementation
1482 SQL-layer acquires IX lock in GLOBAL namespace for each statement
1483 that can modify metadata or data (i.e. for each statement that
1484 needs SW, SU, SNW, SNRW or X object locks). OTOH, to ensure that
1485 DROP DATABASE works correctly with concurrent DDL, IX metadata locks
1486 in SCHEMA namespace are acquired for DDL statements which can update
1487 metadata in the schema (i.e. which acquire SU, SNW, SNRW and X locks
1488 on schema objects) and aren't acquired for DML.
1489 */
1490
1491 const MDL_lock::bitmap_t
1492 MDL_lock::MDL_scoped_lock::m_granted_incompatible[MDL_TYPE_END]=
1493 {
1494 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED),
1495 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_INTENTION_EXCLUSIVE),
1496 0, 0, 0, 0, 0, 0, 0,
1497 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED) | MDL_BIT(MDL_INTENTION_EXCLUSIVE)
1498 };
1499
1500 const MDL_lock::bitmap_t
1501 MDL_lock::MDL_scoped_lock::m_waiting_incompatible[MDL_TYPE_END]=
1502 {
1503 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED),
1504 MDL_BIT(MDL_EXCLUSIVE), 0, 0, 0, 0, 0, 0, 0, 0
1505 };
1506
1507
1508 /**
1509 Compatibility (or rather "incompatibility") matrices for per-object
1510 metadata lock. Arrays of bitmaps which elements specify which granted/
1511 waiting locks are incompatible with type of lock being requested.
1512
1513 The first array specifies if particular type of request can be satisfied
1514 if there is granted lock of certain type.
1515
1516 Request | Granted requests for lock |
1517 type | S SH SR SW SU SRO SNW SNRW X |
1518 ----------+------------------------------------+
1519 S | + + + + + + + + - |
1520 SH | + + + + + + + + - |
1521 SR | + + + + + + + - - |
1522 SW | + + + + + - - - - |
1523 SU | + + + + - + - - - |
1524 SRO | + + + - + + + - - |
1525 SNW | + + + - - + - - - |
1526 SNRW | + + - - - - - - - |
1527 X | - - - - - - - - - |
1528 SU -> X | - - - - 0 - 0 0 0 |
1529 SNW -> X | - - - 0 0 - 0 0 0 |
1530 SNRW -> X | - - 0 0 0 0 0 0 0 |
1531
1532 The second array specifies if particular type of request can be satisfied
1533 if there is waiting request for the same lock of certain type. In other
1534 words it specifies what is the priority of different lock types.
1535
1536 Request | Pending requests for lock |
1537 type | S SH SR SW SU SRO SNW SNRW X |
1538 ----------+-----------------------------------+
1539 S | + + + + + + + + - |
1540 SH | + + + + + + + + + |
1541 SR | + + + + + + + - - |
1542 SW | + + + + + + - - - |
1543 SU | + + + + + + + + - |
1544 SRO | + + + - + + + - - |
1545 SNW | + + + + + + + + - |
1546 SNRW | + + + + + + + + - |
1547 X | + + + + + + + + + |
1548 SU -> X | + + + + + + + + + |
1549 SNW -> X | + + + + + + + + + |
1550 SNRW -> X | + + + + + + + + + |
1551
1552 Here: "+" -- means that request can be satisfied
1553 "-" -- means that request can't be satisfied and should wait
1554 "0" -- means impossible situation which will trigger assert
1555
1556 @note In cases then current context already has "stronger" type
1557 of lock on the object it will be automatically granted
1558 thanks to usage of the MDL_context::find_ticket() method.
1559
1560 @note IX locks are excluded since they are not used for per-object
1561 metadata locks.
1562 */
1563
1564 const MDL_lock::bitmap_t
1565 MDL_lock::MDL_object_lock::m_granted_incompatible[MDL_TYPE_END]=
1566 {
1567 0,
1568 MDL_BIT(MDL_EXCLUSIVE),
1569 MDL_BIT(MDL_EXCLUSIVE),
1570 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
1571 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1572 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
1573 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1574 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE),
1575 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1576 MDL_BIT(MDL_SHARED_WRITE),
1577 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1578 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE) |
1579 MDL_BIT(MDL_SHARED_WRITE),
1580 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1581 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY) |
1582 MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE) |
1583 MDL_BIT(MDL_SHARED_READ),
1584 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1585 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY) |
1586 MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE) |
1587 MDL_BIT(MDL_SHARED_READ) | MDL_BIT(MDL_SHARED_HIGH_PRIO) |
1588 MDL_BIT(MDL_SHARED)
1589 };
1590
1591
1592 const MDL_lock::bitmap_t
1593 MDL_lock::MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END]=
1594 {
1595 0,
1596 MDL_BIT(MDL_EXCLUSIVE),
1597 0,
1598 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
1599 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1600 MDL_BIT(MDL_SHARED_NO_WRITE),
1601 MDL_BIT(MDL_EXCLUSIVE),
1602 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1603 MDL_BIT(MDL_SHARED_WRITE),
1604 MDL_BIT(MDL_EXCLUSIVE),
1605 MDL_BIT(MDL_EXCLUSIVE),
1606 0
1607 };
1608
1609
1610 /**
1611 Compatibility (or rather "incompatibility") matrices for backup metadata
1612 lock. Arrays of bitmaps which elements specify which granted/waiting locks
1613 are incompatible with type of lock being requested.
1614
1615 The first array specifies if particular type of request can be satisfied
1616 if there is granted backup lock of certain type.
1617
1618 Request | Type of active backup lock |
1619 type | S0 S1 S2 S3 S4 F1 F2 D TD SD DD BL AC C |
1620 ----------+---------------------------------------------------------+
1621 S0 | - - - - - + + + + + + + + + |
1622 S1 | - + + + + + + + + + + + + + |
1623 S2 | - + + + + + + - + + + + + + |
1624 S3 | - + + + + + + - + + - + + + |
1625 S4 | - + + + + + + - + - - + + - |
1626 FTWRL1 | + + + + + + + - - - - + - + |
1627 FTWRL2 | + + + + + + + - - - - + - - |
1628 D | + - - - - - - + + + + + + + |
1629 TD | + + + + + - - + + + + + + + |
1630 SD | + + + + - - - + + + + + + + |
1631 DDL | + + + - - - - + + + + - + + |
1632 BLOCK_DDL | + + + + + + + + + + - + + + |
1633 ALTER_COP | + + + + + - - + + + + + + + |
1634 COMMIT | + + + + - + - + + + + + + + |
1635
1636 The second array specifies if particular type of request can be satisfied
1637 if there is already waiting request for the backup lock of certain type.
1638 I.e. it specifies what is the priority of different lock types.
1639
1640 Request | Pending backup lock |
1641 type | S0 S1 S2 S3 S4 F1 F2 D TD SD DD BL AC C |
1642 ----------+---------------------------------------------------------+
1643 S0 | + - - - - + + + + + + + + + |
1644 S1 | + + + + + + + + + + + + + + |
1645 S2 | + + + + + + + + + + + + + + |
1646 S3 | + + + + + + + + + + + + + + |
1647 S4 | + + + + + + + + + + + + + + |
1648 FTWRL1 | + + + + + + + + + + + + + + |
1649 FTWRL2 | + + + + + + + + + + + + + + |
1650 D | + - - - - - - + + + + + + + |
1651 TD | + + + + + - - + + + + + + + |
1652 SD | + + + + - - - + + + + + + + |
1653 DDL | + + + - - - - + + + + - + + |
1654 BLOCK_DDL | + + + + + + + + + + + + + + |
1655 ALTER_COP | + + + + + - - + + + + + + + |
1656 COMMIT | + + + + - + - + + + + + + + |
1657
1658 Here: "+" -- means that request can be satisfied
1659 "-" -- means that request can't be satisfied and should wait
1660 */
1661
1662 /*
1663 NOTE: If you add a new MDL_BACKUP_XXX level lock, you have to also add it
1664 to MDL_BACKUP_START in the two arrays below!
1665 */
1666
1667 const MDL_lock::bitmap_t
1668 MDL_lock::MDL_backup_lock::m_granted_incompatible[MDL_BACKUP_END]=
1669 {
1670 /* MDL_BACKUP_START */
1671 MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT),
1672 MDL_BIT(MDL_BACKUP_START),
1673 MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_DML),
1674 MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_DML) | MDL_BIT(MDL_BACKUP_DDL),
1675 MDL_BIT(MDL_BACKUP_START) | MDL_BIT(MDL_BACKUP_DML) | MDL_BIT(MDL_BACKUP_SYS_DML) | MDL_BIT(MDL_BACKUP_DDL) | MDL_BIT(MDL_BACKUP_COMMIT),
1676
1677 /* MDL_BACKUP_FTWRL1 */
1678 MDL_BIT(MDL_BACKUP_DML) | MDL_BIT(MDL_BACKUP_TRANS_DML) | MDL_BIT(MDL_BACKUP_SYS_DML) | MDL_BIT(MDL_BACKUP_DDL) | MDL_BIT(MDL_BACKUP_ALTER_COPY),
1679 MDL_BIT(MDL_BACKUP_DML) | MDL_BIT(MDL_BACKUP_TRANS_DML) | MDL_BIT(MDL_BACKUP_SYS_DML) | MDL_BIT(MDL_BACKUP_DDL) | MDL_BIT(MDL_BACKUP_ALTER_COPY) | MDL_BIT(MDL_BACKUP_COMMIT),
1680 /* MDL_BACKUP_DML */
1681 MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1682 MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1683 MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1684 /* MDL_BACKUP_DDL */
1685 MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2) | MDL_BIT(MDL_BACKUP_BLOCK_DDL),
1686 /* MDL_BACKUP_BLOCK_DDL */
1687 MDL_BIT(MDL_BACKUP_DDL),
1688 MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1689 /* MDL_BACKUP_COMMIT */
1690 MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL2)
1691 };
1692
1693
1694 const MDL_lock::bitmap_t
1695 MDL_lock::MDL_backup_lock::m_waiting_incompatible[MDL_BACKUP_END]=
1696 {
1697 /* MDL_BACKUP_START */
1698 MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT),
1699 0,
1700 0,
1701 0,
1702 0,
1703 /* MDL_BACKUP_FTWRL1 */
1704 0,
1705 0,
1706
1707 /* MDL_BACKUP_DML */
1708 MDL_BIT(MDL_BACKUP_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_FLUSH) | MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1709 MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1710 MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1711 /* MDL_BACKUP_DDL */
1712 MDL_BIT(MDL_BACKUP_WAIT_DDL) | MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2) | MDL_BIT(MDL_BACKUP_BLOCK_DDL),
1713 /* MDL_BACKUP_BLOCK_DDL */
1714 0,
1715 MDL_BIT(MDL_BACKUP_FTWRL1) | MDL_BIT(MDL_BACKUP_FTWRL2),
1716 /* MDL_BACKUP_COMMIT */
1717 MDL_BIT(MDL_BACKUP_WAIT_COMMIT) | MDL_BIT(MDL_BACKUP_FTWRL2)
1718 };
1719
1720
1721 /**
1722 Check if request for the metadata lock can be satisfied given its
1723 current state.
1724
1725 New lock request can be satisfied iff:
1726 - There are no incompatible types of satisfied requests
1727 in other contexts
1728 - There are no waiting requests which have higher priority
1729 than this request when priority was not ignored.
1730
1731 @param type_arg The requested lock type.
1732 @param requestor_ctx The MDL context of the requestor.
1733 @param ignore_lock_priority Ignore lock priority.
1734
1735 @retval TRUE Lock request can be satisfied
1736 @retval FALSE There is some conflicting lock.
1737
1738 @note In cases then current context already has "stronger" type
1739 of lock on the object it will be automatically granted
1740 thanks to usage of the MDL_context::find_ticket() method.
1741 */
1742
1743 bool
can_grant_lock(enum_mdl_type type_arg,MDL_context * requestor_ctx,bool ignore_lock_priority) const1744 MDL_lock::can_grant_lock(enum_mdl_type type_arg,
1745 MDL_context *requestor_ctx,
1746 bool ignore_lock_priority) const
1747 {
1748 bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg];
1749 bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg];
1750
1751 #ifdef WITH_WSREP
1752 /*
1753 Approve lock request in BACKUP namespace for BF threads.
1754 We should get rid of this code and forbid FTWRL/BACKUP statements
1755 when wsrep is active.
1756 */
1757 if ((wsrep_thd_is_toi(requestor_ctx->get_thd()) ||
1758 wsrep_thd_is_applying(requestor_ctx->get_thd())) &&
1759 key.mdl_namespace() == MDL_key::BACKUP)
1760 {
1761 bool waiting_incompatible= m_waiting.bitmap() & waiting_incompat_map;
1762 bool granted_incompatible= m_granted.bitmap() & granted_incompat_map;
1763 if (waiting_incompatible || granted_incompatible)
1764 {
1765 WSREP_DEBUG("global lock granted for BF%s: %lu %s",
1766 waiting_incompatible ? " (waiting queue)" : "",
1767 thd_get_thread_id(requestor_ctx->get_thd()),
1768 wsrep_thd_query(requestor_ctx->get_thd()));
1769 }
1770 return true;
1771 }
1772 #endif /* WITH_WSREP */
1773
1774 if (!ignore_lock_priority && (m_waiting.bitmap() & waiting_incompat_map))
1775 return false;
1776
1777 if (m_granted.bitmap() & granted_incompat_map)
1778 {
1779 Ticket_iterator it(m_granted);
1780 bool can_grant= true;
1781
1782 /* Check that the incompatible lock belongs to some other context. */
1783 while (auto ticket= it++)
1784 {
1785 if (ticket->get_ctx() != requestor_ctx &&
1786 ticket->is_incompatible_when_granted(type_arg))
1787 {
1788 can_grant= false;
1789 #ifdef WITH_WSREP
1790 /*
1791 non WSREP threads must report conflict immediately
1792 note: RSU processing wsrep threads, have wsrep_on==OFF
1793 */
1794 if (WSREP(requestor_ctx->get_thd()) ||
1795 requestor_ctx->get_thd()->wsrep_cs().mode() ==
1796 wsrep::client_state::m_rsu)
1797 {
1798 wsrep_handle_mdl_conflict(requestor_ctx, ticket, &key);
1799 if (wsrep_log_conflicts)
1800 {
1801 auto key= ticket->get_key();
1802 WSREP_INFO("MDL conflict db=%s table=%s ticket=%d solved by abort",
1803 key->db_name(), key->name(), ticket->get_type());
1804 }
1805 continue;
1806 }
1807 #endif /* WITH_WSREP */
1808 break;
1809 }
1810 }
1811 return can_grant;
1812 }
1813 return true;
1814 }
1815
1816
1817 /**
1818 Return thread id of the thread to which the first ticket was
1819 granted.
1820 */
1821
1822 inline unsigned long
get_lock_owner() const1823 MDL_lock::get_lock_owner() const
1824 {
1825 Ticket_iterator it(m_granted);
1826 MDL_ticket *ticket;
1827
1828 if ((ticket= it++))
1829 return ticket->get_ctx()->get_thread_id();
1830 return 0;
1831 }
1832
1833
1834 /** Remove a ticket from waiting or pending queue and wakeup up waiters. */
1835
remove_ticket(LF_PINS * pins,Ticket_list MDL_lock::* list,MDL_ticket * ticket)1836 void MDL_lock::remove_ticket(LF_PINS *pins, Ticket_list MDL_lock::*list,
1837 MDL_ticket *ticket)
1838 {
1839 mysql_prlock_wrlock(&m_rwlock);
1840 (this->*list).remove_ticket(ticket);
1841 if (is_empty())
1842 mdl_locks.remove(pins, this);
1843 else
1844 {
1845 /*
1846 There can be some contexts waiting to acquire a lock
1847 which now might be able to do it. Grant the lock to
1848 them and wake them up!
1849
1850 We always try to reschedule locks, since there is no easy way
1851 (i.e. by looking at the bitmaps) to find out whether it is
1852 required or not.
1853 In a general case, even when the queue's bitmap is not changed
1854 after removal of the ticket, there is a chance that some request
1855 can be satisfied (due to the fact that a granted request
1856 reflected in the bitmap might belong to the same context as a
1857 pending request).
1858 */
1859 reschedule_waiters();
1860 mysql_prlock_unlock(&m_rwlock);
1861 }
1862 }
1863
1864
1865 /**
1866 Check if we have any pending locks which conflict with existing
1867 shared lock.
1868
1869 @pre The ticket must match an acquired lock.
1870
1871 @return TRUE if there is a conflicting lock request, FALSE otherwise.
1872 */
1873
has_pending_conflicting_lock(enum_mdl_type type)1874 bool MDL_lock::has_pending_conflicting_lock(enum_mdl_type type)
1875 {
1876 bool result;
1877
1878 mysql_prlock_rdlock(&m_rwlock);
1879 result= (m_waiting.bitmap() & incompatible_granted_types_bitmap()[type]);
1880 mysql_prlock_unlock(&m_rwlock);
1881 return result;
1882 }
1883
1884
~MDL_wait_for_graph_visitor()1885 MDL_wait_for_graph_visitor::~MDL_wait_for_graph_visitor()
1886 {
1887 }
1888
1889
~MDL_wait_for_subgraph()1890 MDL_wait_for_subgraph::~MDL_wait_for_subgraph()
1891 {
1892 }
1893
1894 /**
1895 Check if ticket represents metadata lock of "stronger" or equal type
1896 than specified one. I.e. if metadata lock represented by ticket won't
1897 allow any of locks which are not allowed by specified type of lock.
1898
1899 @return TRUE if ticket has stronger or equal type
1900 FALSE otherwise.
1901 */
1902
has_stronger_or_equal_type(enum_mdl_type type) const1903 bool MDL_ticket::has_stronger_or_equal_type(enum_mdl_type type) const
1904 {
1905 const MDL_lock::bitmap_t *
1906 granted_incompat_map= m_lock->incompatible_granted_types_bitmap();
1907
1908 return ! (granted_incompat_map[type] & ~(granted_incompat_map[m_type]));
1909 }
1910
1911
is_incompatible_when_granted(enum_mdl_type type) const1912 bool MDL_ticket::is_incompatible_when_granted(enum_mdl_type type) const
1913 {
1914 return (MDL_BIT(m_type) &
1915 m_lock->incompatible_granted_types_bitmap()[type]);
1916 }
1917
1918
is_incompatible_when_waiting(enum_mdl_type type) const1919 bool MDL_ticket::is_incompatible_when_waiting(enum_mdl_type type) const
1920 {
1921 return (MDL_BIT(m_type) &
1922 m_lock->incompatible_waiting_types_bitmap()[type]);
1923 }
1924
1925
1926 static const LEX_STRING
get_mdl_lock_name(MDL_key::enum_mdl_namespace mdl_namespace,enum_mdl_type type)1927 *get_mdl_lock_name(MDL_key::enum_mdl_namespace mdl_namespace,
1928 enum_mdl_type type)
1929 {
1930 return mdl_namespace == MDL_key::BACKUP ?
1931 &backup_lock_types[type] :
1932 &lock_types[type];
1933 }
1934
1935
get_type_name() const1936 const LEX_STRING *MDL_ticket::get_type_name() const
1937 {
1938 return get_mdl_lock_name(get_key()->mdl_namespace(), m_type);
1939 }
1940
get_type_name(enum_mdl_type type) const1941 const LEX_STRING *MDL_ticket::get_type_name(enum_mdl_type type) const
1942 {
1943 return get_mdl_lock_name(get_key()->mdl_namespace(), type);
1944 }
1945
1946
1947 /**
1948 Check whether the context already holds a compatible lock ticket
1949 on an object.
1950 Start searching from list of locks for the same duration as lock
1951 being requested. If not look at lists for other durations.
1952
1953 @param mdl_request Lock request object for lock to be acquired
1954 @param[out] result_duration Duration of lock which was found.
1955
1956 @note Tickets which correspond to lock types "stronger" than one
1957 being requested are also considered compatible.
1958
1959 @return A pointer to the lock ticket for the object or NULL otherwise.
1960 */
1961
1962 MDL_ticket *
find_ticket(MDL_request * mdl_request,enum_mdl_duration * result_duration)1963 MDL_context::find_ticket(MDL_request *mdl_request,
1964 enum_mdl_duration *result_duration)
1965 {
1966 MDL_ticket *ticket;
1967 int i;
1968
1969 for (i= 0; i < MDL_DURATION_END; i++)
1970 {
1971 enum_mdl_duration duration= (enum_mdl_duration)((mdl_request->duration+i) %
1972 MDL_DURATION_END);
1973 Ticket_iterator it(m_tickets[duration]);
1974
1975 while ((ticket= it++))
1976 {
1977 if (mdl_request->key.is_equal(&ticket->m_lock->key) &&
1978 ticket->has_stronger_or_equal_type(mdl_request->type))
1979 {
1980 DBUG_PRINT("info", ("Adding mdl lock %s to %s",
1981 get_mdl_lock_name(mdl_request->key.mdl_namespace(),
1982 mdl_request->type)->str,
1983 ticket->get_type_name()->str));
1984 *result_duration= duration;
1985 return ticket;
1986 }
1987 }
1988 }
1989 return NULL;
1990 }
1991
1992
1993 /**
1994 Try to acquire one lock.
1995
1996 Unlike exclusive locks, shared locks are acquired one by
1997 one. This is interface is chosen to simplify introduction of
1998 the new locking API to the system. MDL_context::try_acquire_lock()
1999 is currently used from open_table(), and there we have only one
2000 table to work with.
2001
2002 This function may also be used to try to acquire an exclusive
2003 lock on a destination table, by ALTER TABLE ... RENAME.
2004
2005 Returns immediately without any side effect if encounters a lock
2006 conflict. Otherwise takes the lock.
2007
2008 FIXME: Compared to lock_table_name_if_not_cached() (from 5.1)
2009 it gives slightly more false negatives.
2010
2011 @param mdl_request [in/out] Lock request object for lock to be acquired
2012
2013 @retval FALSE Success. The lock may have not been acquired.
2014 Check the ticket, if it's NULL, a conflicting lock
2015 exists.
2016 @retval TRUE Out of resources, an error has been reported.
2017 */
2018
2019 bool
try_acquire_lock(MDL_request * mdl_request)2020 MDL_context::try_acquire_lock(MDL_request *mdl_request)
2021 {
2022 MDL_ticket *ticket;
2023
2024 if (try_acquire_lock_impl(mdl_request, &ticket))
2025 return TRUE;
2026
2027 if (! mdl_request->ticket)
2028 {
2029 /*
2030 Our attempt to acquire lock without waiting has failed.
2031 Let us release resources which were acquired in the process.
2032 We can't get here if we allocated a new lock object so there
2033 is no need to release it.
2034 */
2035 DBUG_ASSERT(! ticket->m_lock->is_empty());
2036 mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
2037 MDL_ticket::destroy(ticket);
2038 }
2039
2040 return FALSE;
2041 }
2042
2043
2044 /**
2045 Auxiliary method for acquiring lock without waiting.
2046
2047 @param mdl_request [in/out] Lock request object for lock to be acquired
2048 @param out_ticket [out] Ticket for the request in case when lock
2049 has not been acquired.
2050
2051 @retval FALSE Success. The lock may have not been acquired.
2052 Check MDL_request::ticket, if it's NULL, a conflicting
2053 lock exists. In this case "out_ticket" out parameter
2054 points to ticket which was constructed for the request.
2055 MDL_ticket::m_lock points to the corresponding MDL_lock
2056 object and MDL_lock::m_rwlock write-locked.
2057 @retval TRUE Out of resources, an error has been reported.
2058 */
2059
2060 bool
try_acquire_lock_impl(MDL_request * mdl_request,MDL_ticket ** out_ticket)2061 MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
2062 MDL_ticket **out_ticket)
2063 {
2064 MDL_lock *lock;
2065 MDL_key *key= &mdl_request->key;
2066 MDL_ticket *ticket;
2067 enum_mdl_duration found_duration;
2068
2069 /* Don't take chances in production. */
2070 DBUG_ASSERT(mdl_request->ticket == NULL);
2071 mdl_request->ticket= NULL;
2072
2073 /*
2074 Check whether the context already holds a shared lock on the object,
2075 and if so, grant the request.
2076 */
2077 if ((ticket= find_ticket(mdl_request, &found_duration)))
2078 {
2079 DBUG_ASSERT(ticket->m_lock);
2080 DBUG_ASSERT(ticket->has_stronger_or_equal_type(mdl_request->type));
2081 /*
2082 If the request is for a transactional lock, and we found
2083 a transactional lock, just reuse the found ticket.
2084
2085 It's possible that we found a transactional lock,
2086 but the request is for a HANDLER lock. In that case HANDLER
2087 code will clone the ticket (see below why it's needed).
2088
2089 If the request is for a transactional lock, and we found
2090 a HANDLER lock, create a copy, to make sure that when user
2091 does HANDLER CLOSE, the transactional lock is not released.
2092
2093 If the request is for a handler lock, and we found a
2094 HANDLER lock, also do the clone. HANDLER CLOSE for one alias
2095 should not release the lock on the table HANDLER opened through
2096 a different alias.
2097 */
2098 mdl_request->ticket= ticket;
2099 if ((found_duration != mdl_request->duration ||
2100 mdl_request->duration == MDL_EXPLICIT) &&
2101 clone_ticket(mdl_request))
2102 {
2103 /* Clone failed. */
2104 mdl_request->ticket= NULL;
2105 return TRUE;
2106 }
2107 return FALSE;
2108 }
2109
2110 if (fix_pins())
2111 return TRUE;
2112
2113 if (!(ticket= MDL_ticket::create(this, mdl_request->type
2114 #ifndef DBUG_OFF
2115 , mdl_request->duration
2116 #endif
2117 )))
2118 return TRUE;
2119
2120 /* The below call implicitly locks MDL_lock::m_rwlock on success. */
2121 if (!(lock= mdl_locks.find_or_insert(m_pins, key)))
2122 {
2123 MDL_ticket::destroy(ticket);
2124 return TRUE;
2125 }
2126
2127 ticket->m_lock= lock;
2128
2129 if (lock->can_grant_lock(mdl_request->type, this, false))
2130 {
2131 lock->m_granted.add_ticket(ticket);
2132
2133 mysql_prlock_unlock(&lock->m_rwlock);
2134
2135 m_tickets[mdl_request->duration].push_front(ticket);
2136
2137 mdl_request->ticket= ticket;
2138 }
2139 else
2140 *out_ticket= ticket;
2141
2142 return FALSE;
2143 }
2144
2145
2146 /**
2147 Create a copy of a granted ticket.
2148 This is used to make sure that HANDLER ticket
2149 is never shared with a ticket that belongs to
2150 a transaction, so that when we HANDLER CLOSE,
2151 we don't release a transactional ticket, and
2152 vice versa -- when we COMMIT, we don't mistakenly
2153 release a ticket for an open HANDLER.
2154
2155 @retval TRUE Out of memory.
2156 @retval FALSE Success.
2157 */
2158
2159 bool
clone_ticket(MDL_request * mdl_request)2160 MDL_context::clone_ticket(MDL_request *mdl_request)
2161 {
2162 MDL_ticket *ticket;
2163
2164
2165 /*
2166 Since in theory we can clone ticket belonging to a different context
2167 we need to prepare target context for possible attempts to release
2168 lock and thus possible removal of MDL_lock from MDL_map container.
2169 So we allocate pins to be able to work with this container if they
2170 are not allocated already.
2171 */
2172 if (fix_pins())
2173 return TRUE;
2174
2175 /*
2176 By submitting mdl_request->type to MDL_ticket::create()
2177 we effectively downgrade the cloned lock to the level of
2178 the request.
2179 */
2180 if (!(ticket= MDL_ticket::create(this, mdl_request->type
2181 #ifndef DBUG_OFF
2182 , mdl_request->duration
2183 #endif
2184 )))
2185 return TRUE;
2186
2187 /* clone() is not supposed to be used to get a stronger lock. */
2188 DBUG_ASSERT(mdl_request->ticket->has_stronger_or_equal_type(ticket->m_type));
2189
2190 ticket->m_lock= mdl_request->ticket->m_lock;
2191 mdl_request->ticket= ticket;
2192
2193 mysql_prlock_wrlock(&ticket->m_lock->m_rwlock);
2194 ticket->m_lock->m_granted.add_ticket(ticket);
2195 mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
2196
2197 m_tickets[mdl_request->duration].push_front(ticket);
2198
2199 return FALSE;
2200 }
2201
2202
2203 /**
2204 Check if there is any conflicting lock that could cause this thread
2205 to wait for another thread which is not ready to commit.
2206 This is always an error, as the upper level of parallel replication
2207 should not allow a scheduling of a conflicting DDL until all earlier
2208 transactions has commited.
2209
2210 This function is only called for a slave using parallel replication
2211 and trying to get an exclusive lock for the table.
2212 */
2213
2214 #ifndef DBUG_OFF
check_if_conflicting_replication_locks(MDL_context * ctx)2215 bool MDL_lock::check_if_conflicting_replication_locks(MDL_context *ctx)
2216 {
2217 Ticket_iterator it(m_granted);
2218 MDL_ticket *conflicting_ticket;
2219 rpl_group_info *rgi_slave= ctx->get_thd()->rgi_slave;
2220
2221 if (!rgi_slave->gtid_sub_id)
2222 return 0;
2223
2224 while ((conflicting_ticket= it++))
2225 {
2226 if (conflicting_ticket->get_ctx() != ctx)
2227 {
2228 MDL_context *conflicting_ctx= conflicting_ticket->get_ctx();
2229 rpl_group_info *conflicting_rgi_slave;
2230 conflicting_rgi_slave= conflicting_ctx->get_thd()->rgi_slave;
2231
2232 /*
2233 If the conflicting thread is another parallel replication
2234 thread for the same master and it's not in commit stage, then
2235 the current transaction has started too early and something is
2236 seriously wrong.
2237 */
2238 if (conflicting_rgi_slave &&
2239 conflicting_rgi_slave->gtid_sub_id &&
2240 conflicting_rgi_slave->rli == rgi_slave->rli &&
2241 conflicting_rgi_slave->current_gtid.domain_id ==
2242 rgi_slave->current_gtid.domain_id &&
2243 !conflicting_rgi_slave->did_mark_start_commit)
2244 return 1; // Fatal error
2245 }
2246 }
2247 return 0;
2248 }
2249 #endif
2250
2251
2252 /**
2253 Acquire one lock with waiting for conflicting locks to go away if needed.
2254
2255 @param mdl_request [in/out] Lock request object for lock to be acquired
2256
2257 @param lock_wait_timeout [in] Seconds to wait before timeout.
2258
2259 @retval FALSE Success. MDL_request::ticket points to the ticket
2260 for the lock.
2261 @retval TRUE Failure (Out of resources or waiting is aborted),
2262 */
2263
2264 bool
acquire_lock(MDL_request * mdl_request,double lock_wait_timeout)2265 MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout)
2266 {
2267 MDL_lock *lock;
2268 MDL_ticket *ticket;
2269 MDL_wait::enum_wait_status wait_status;
2270 DBUG_ENTER("MDL_context::acquire_lock");
2271 DBUG_PRINT("enter", ("lock_type: %s timeout: %f",
2272 get_mdl_lock_name(mdl_request->key.mdl_namespace(),
2273 mdl_request->type)->str,
2274 lock_wait_timeout));
2275
2276 if (try_acquire_lock_impl(mdl_request, &ticket))
2277 DBUG_RETURN(TRUE);
2278
2279 if (mdl_request->ticket)
2280 {
2281 /*
2282 We have managed to acquire lock without waiting.
2283 MDL_lock, MDL_context and MDL_request were updated
2284 accordingly, so we can simply return success.
2285 */
2286 DBUG_PRINT("info", ("Got lock without waiting"));
2287 DBUG_RETURN(FALSE);
2288 }
2289
2290 /*
2291 Our attempt to acquire lock without waiting has failed.
2292 As a result of this attempt we got MDL_ticket with m_lock
2293 member pointing to the corresponding MDL_lock object which
2294 has MDL_lock::m_rwlock write-locked.
2295 */
2296 lock= ticket->m_lock;
2297
2298 if (lock_wait_timeout == 0)
2299 {
2300 mysql_prlock_unlock(&lock->m_rwlock);
2301 MDL_ticket::destroy(ticket);
2302 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
2303 DBUG_RETURN(TRUE);
2304 }
2305
2306 lock->m_waiting.add_ticket(ticket);
2307
2308 /*
2309 Once we added a pending ticket to the waiting queue,
2310 we must ensure that our wait slot is empty, so
2311 that our lock request can be scheduled. Do that in the
2312 critical section formed by the acquired write lock on MDL_lock.
2313 */
2314 m_wait.reset_status();
2315
2316 /*
2317 Don't break conflicting locks if timeout is 0 as 0 is used
2318 To check if there is any conflicting locks...
2319 */
2320 if (lock->needs_notification(ticket) && lock_wait_timeout)
2321 lock->notify_conflicting_locks(this);
2322
2323 /*
2324 Ensure that if we are trying to get an exclusive lock for a slave
2325 running parallel replication, then we are not blocked by another
2326 parallel slave thread that is not committed. This should never happen as
2327 the parallel replication scheduler should never schedule a DDL while
2328 DML's are still running.
2329 */
2330 DBUG_SLOW_ASSERT((mdl_request->type != MDL_INTENTION_EXCLUSIVE &&
2331 mdl_request->type != MDL_EXCLUSIVE) ||
2332 !(get_thd()->rgi_slave &&
2333 get_thd()->rgi_slave->is_parallel_exec &&
2334 lock->check_if_conflicting_replication_locks(this)));
2335
2336 mysql_prlock_unlock(&lock->m_rwlock);
2337
2338 will_wait_for(ticket);
2339
2340 /* There is a shared or exclusive lock on the object. */
2341 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait");
2342
2343 find_deadlock();
2344
2345 struct timespec abs_timeout, abs_shortwait;
2346 set_timespec_nsec(abs_timeout,
2347 (ulonglong)(lock_wait_timeout * 1000000000ULL));
2348 set_timespec(abs_shortwait, 1);
2349 wait_status= MDL_wait::EMPTY;
2350
2351 while (cmp_timespec(abs_shortwait, abs_timeout) <= 0)
2352 {
2353 /* abs_timeout is far away. Wait a short while and notify locks. */
2354 wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE,
2355 mdl_request->key.get_wait_state_name());
2356
2357 if (wait_status != MDL_wait::EMPTY)
2358 break;
2359 /* Check if the client is gone while we were waiting. */
2360 if (! thd_is_connected(m_owner->get_thd()))
2361 {
2362 /*
2363 * The client is disconnected. Don't wait forever:
2364 * assume it's the same as a wait timeout, this
2365 * ensures all error handling is correct.
2366 */
2367 wait_status= MDL_wait::TIMEOUT;
2368 break;
2369 }
2370
2371 mysql_prlock_wrlock(&lock->m_rwlock);
2372 if (lock->needs_notification(ticket))
2373 lock->notify_conflicting_locks(this);
2374 mysql_prlock_unlock(&lock->m_rwlock);
2375 set_timespec(abs_shortwait, 1);
2376 }
2377 if (wait_status == MDL_wait::EMPTY)
2378 wait_status= m_wait.timed_wait(m_owner, &abs_timeout, TRUE,
2379 mdl_request->key.get_wait_state_name());
2380
2381 done_waiting_for();
2382
2383 if (wait_status != MDL_wait::GRANTED)
2384 {
2385 lock->remove_ticket(m_pins, &MDL_lock::m_waiting, ticket);
2386 MDL_ticket::destroy(ticket);
2387 switch (wait_status)
2388 {
2389 case MDL_wait::VICTIM:
2390 DBUG_LOCK_FILE;
2391 DBUG_PRINT("mdl_locks", ("%s", mdl_dbug_print_locks()));
2392 DBUG_UNLOCK_FILE;
2393 my_error(ER_LOCK_DEADLOCK, MYF(0));
2394 break;
2395 case MDL_wait::TIMEOUT:
2396 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
2397 break;
2398 case MDL_wait::KILLED:
2399 get_thd()->send_kill_message();
2400 break;
2401 default:
2402 DBUG_ASSERT(0);
2403 break;
2404 }
2405 DBUG_RETURN(TRUE);
2406 }
2407
2408 /*
2409 We have been granted our request.
2410 State of MDL_lock object is already being appropriately updated by a
2411 concurrent thread (@sa MDL_lock:reschedule_waiters()).
2412 So all we need to do is to update MDL_context and MDL_request objects.
2413 */
2414 DBUG_ASSERT(wait_status == MDL_wait::GRANTED);
2415
2416 m_tickets[mdl_request->duration].push_front(ticket);
2417
2418 mdl_request->ticket= ticket;
2419
2420 DBUG_RETURN(FALSE);
2421 }
2422
2423
mdl_request_ptr_cmp(const void * ptr1,const void * ptr2)2424 extern "C" int mdl_request_ptr_cmp(const void* ptr1, const void* ptr2)
2425 {
2426 MDL_request *req1= *(MDL_request**)ptr1;
2427 MDL_request *req2= *(MDL_request**)ptr2;
2428 return req1->key.cmp(&req2->key);
2429 }
2430
2431
2432 /**
2433 Acquire exclusive locks. There must be no granted locks in the
2434 context.
2435
2436 This is a replacement of lock_table_names(). It is used in
2437 RENAME, DROP and other DDL SQL statements.
2438
2439 @param mdl_requests List of requests for locks to be acquired.
2440
2441 @param lock_wait_timeout Seconds to wait before timeout.
2442
2443 @note The list of requests should not contain non-exclusive lock requests.
2444 There should not be any acquired locks in the context.
2445
2446 @note Assumes that one already owns scoped intention exclusive lock.
2447
2448 @retval FALSE Success
2449 @retval TRUE Failure
2450 */
2451
acquire_locks(MDL_request_list * mdl_requests,double lock_wait_timeout)2452 bool MDL_context::acquire_locks(MDL_request_list *mdl_requests,
2453 double lock_wait_timeout)
2454 {
2455 MDL_request_list::Iterator it(*mdl_requests);
2456 MDL_request **sort_buf, **p_req;
2457 MDL_savepoint mdl_svp= mdl_savepoint();
2458 ssize_t req_count= static_cast<ssize_t>(mdl_requests->elements());
2459 DBUG_ENTER("MDL_context::acquire_locks");
2460
2461 if (req_count == 0)
2462 DBUG_RETURN(FALSE);
2463
2464 /* Sort requests according to MDL_key. */
2465 if (! (sort_buf= (MDL_request **)my_malloc(req_count *
2466 sizeof(MDL_request*),
2467 MYF(MY_WME))))
2468 DBUG_RETURN(TRUE);
2469
2470 for (p_req= sort_buf; p_req < sort_buf + req_count; p_req++)
2471 *p_req= it++;
2472
2473 my_qsort(sort_buf, req_count, sizeof(MDL_request*),
2474 mdl_request_ptr_cmp);
2475
2476 for (p_req= sort_buf; p_req < sort_buf + req_count; p_req++)
2477 {
2478 if (acquire_lock(*p_req, lock_wait_timeout))
2479 goto err;
2480 }
2481 my_free(sort_buf);
2482 DBUG_RETURN(FALSE);
2483
2484 err:
2485 /*
2486 Release locks we have managed to acquire so far.
2487 Use rollback_to_savepoint() since there may be duplicate
2488 requests that got assigned the same ticket.
2489 */
2490 rollback_to_savepoint(mdl_svp);
2491 /* Reset lock requests back to its initial state. */
2492 for (req_count= p_req - sort_buf, p_req= sort_buf;
2493 p_req < sort_buf + req_count; p_req++)
2494 {
2495 (*p_req)->ticket= NULL;
2496 }
2497 my_free(sort_buf);
2498 DBUG_RETURN(TRUE);
2499 }
2500
2501
2502 /**
2503 Upgrade a shared metadata lock.
2504
2505 Used in ALTER TABLE.
2506
2507 @param mdl_ticket Lock to upgrade.
2508 @param new_type Lock type to upgrade to.
2509 @param lock_wait_timeout Seconds to wait before timeout.
2510
2511 @note In case of failure to upgrade lock (e.g. because upgrader
2512 was killed) leaves lock in its original state (locked in
2513 shared mode).
2514
2515 @note There can be only one upgrader for a lock or we will have deadlock.
2516 This invariant is ensured by the fact that upgradeable locks SU, SNW
2517 and SNRW are not compatible with each other and themselves.
2518
2519 @retval FALSE Success
2520 @retval TRUE Failure (thread was killed)
2521 */
2522
2523 bool
upgrade_shared_lock(MDL_ticket * mdl_ticket,enum_mdl_type new_type,double lock_wait_timeout)2524 MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket,
2525 enum_mdl_type new_type,
2526 double lock_wait_timeout)
2527 {
2528 MDL_request mdl_xlock_request;
2529 MDL_savepoint mdl_svp= mdl_savepoint();
2530 bool is_new_ticket;
2531 DBUG_ENTER("MDL_context::upgrade_shared_lock");
2532 DBUG_PRINT("enter",("old_type: %s new_type: %s lock_wait_timeout: %f",
2533 mdl_ticket->get_type_name()->str,
2534 mdl_ticket->get_type_name(new_type)->str,
2535 lock_wait_timeout));
2536 DEBUG_SYNC(get_thd(), "mdl_upgrade_lock");
2537
2538 /*
2539 Do nothing if already upgraded. Used when we FLUSH TABLE under
2540 LOCK TABLES and a table is listed twice in LOCK TABLES list.
2541
2542 In BACKUP namespace upgrade must always happen. Even though
2543 MDL_BACKUP_START is not stronger than MDL_BACKUP_FLUSH from
2544 has_stronger_or_equal_type(), the latter effectively blocks
2545 new MDL_BACKUP_DML while the former doesn't.
2546 */
2547 if (mdl_ticket->has_stronger_or_equal_type(new_type) &&
2548 mdl_ticket->get_key()->mdl_namespace() != MDL_key::BACKUP)
2549 DBUG_RETURN(FALSE);
2550
2551 mdl_xlock_request.init(&mdl_ticket->m_lock->key, new_type,
2552 MDL_TRANSACTION);
2553
2554 if (acquire_lock(&mdl_xlock_request, lock_wait_timeout))
2555 DBUG_RETURN(TRUE);
2556
2557 is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket);
2558
2559 /* Merge the acquired and the original lock. @todo: move to a method. */
2560 mysql_prlock_wrlock(&mdl_ticket->m_lock->m_rwlock);
2561 if (is_new_ticket)
2562 mdl_ticket->m_lock->m_granted.remove_ticket(mdl_xlock_request.ticket);
2563 /*
2564 Set the new type of lock in the ticket. To update state of
2565 MDL_lock object correctly we need to temporarily exclude
2566 ticket from the granted queue and then include it back.
2567 */
2568 mdl_ticket->m_lock->m_granted.remove_ticket(mdl_ticket);
2569 mdl_ticket->m_type= new_type;
2570 mdl_ticket->m_lock->m_granted.add_ticket(mdl_ticket);
2571
2572 mysql_prlock_unlock(&mdl_ticket->m_lock->m_rwlock);
2573
2574 if (is_new_ticket)
2575 {
2576 m_tickets[MDL_TRANSACTION].remove(mdl_xlock_request.ticket);
2577 MDL_ticket::destroy(mdl_xlock_request.ticket);
2578 }
2579
2580 DBUG_RETURN(FALSE);
2581 }
2582
2583
2584 /**
2585 A fragment of recursive traversal of the wait-for graph
2586 in search for deadlocks. Direct the deadlock visitor to all
2587 contexts that own the lock the current node in the wait-for
2588 graph is waiting for.
2589 As long as the initial node is remembered in the visitor,
2590 a deadlock is found when the same node is seen twice.
2591 */
2592
visit_subgraph(MDL_ticket * waiting_ticket,MDL_wait_for_graph_visitor * gvisitor)2593 bool MDL_lock::visit_subgraph(MDL_ticket *waiting_ticket,
2594 MDL_wait_for_graph_visitor *gvisitor)
2595 {
2596 MDL_ticket *ticket;
2597 MDL_context *src_ctx= waiting_ticket->get_ctx();
2598 bool result= TRUE;
2599
2600 mysql_prlock_rdlock(&m_rwlock);
2601
2602 /* Must be initialized after taking a read lock. */
2603 Ticket_iterator granted_it(m_granted);
2604 Ticket_iterator waiting_it(m_waiting);
2605
2606 /*
2607 MDL_lock's waiting and granted queues and MDL_context::m_waiting_for
2608 member are updated by different threads when the lock is granted
2609 (see MDL_context::acquire_lock() and MDL_lock::reschedule_waiters()).
2610 As a result, here we may encounter a situation when MDL_lock data
2611 already reflects the fact that the lock was granted but
2612 m_waiting_for member has not been updated yet.
2613
2614 For example, imagine that:
2615
2616 thread1: Owns SNW lock on table t1.
2617 thread2: Attempts to acquire SW lock on t1,
2618 but sees an active SNW lock.
2619 Thus adds the ticket to the waiting queue and
2620 sets m_waiting_for to point to the ticket.
2621 thread1: Releases SNW lock, updates MDL_lock object to
2622 grant SW lock to thread2 (moves the ticket for
2623 SW from waiting to the active queue).
2624 Attempts to acquire a new SNW lock on t1,
2625 sees an active SW lock (since it is present in the
2626 active queue), adds ticket for SNW lock to the waiting
2627 queue, sets m_waiting_for to point to this ticket.
2628
2629 At this point deadlock detection algorithm run by thread1 will see that:
2630 - Thread1 waits for SNW lock on t1 (since m_waiting_for is set).
2631 - SNW lock is not granted, because it conflicts with active SW lock
2632 owned by thread 2 (since ticket for SW is present in granted queue).
2633 - Thread2 waits for SW lock (since its m_waiting_for has not been
2634 updated yet!).
2635 - SW lock is not granted because there is pending SNW lock from thread1.
2636 Therefore deadlock should exist [sic!].
2637
2638 To avoid detection of such false deadlocks we need to check the "actual"
2639 status of the ticket being waited for, before analyzing its blockers.
2640 We do this by checking the wait status of the context which is waiting
2641 for it. To avoid races this has to be done under protection of
2642 MDL_lock::m_rwlock lock.
2643 */
2644 if (src_ctx->m_wait.get_status() != MDL_wait::EMPTY)
2645 {
2646 result= FALSE;
2647 goto end;
2648 }
2649
2650 /*
2651 To avoid visiting nodes which were already marked as victims of
2652 deadlock detection (or whose requests were already satisfied) we
2653 enter the node only after peeking at its wait status.
2654 This is necessary to avoid active waiting in a situation
2655 when previous searches for a deadlock already selected the
2656 node we're about to enter as a victim (see the comment
2657 in MDL_context::find_deadlock() for explanation why several searches
2658 can be performed for the same wait).
2659 There is no guarantee that the node isn't chosen a victim while we
2660 are visiting it but this is OK: in the worst case we might do some
2661 extra work and one more context might be chosen as a victim.
2662 */
2663 if (gvisitor->enter_node(src_ctx))
2664 goto end;
2665
2666 /*
2667 We do a breadth-first search first -- that is, inspect all
2668 edges of the current node, and only then follow up to the next
2669 node. In workloads that involve wait-for graph loops this
2670 has proven to be a more efficient strategy [citation missing].
2671 */
2672 while ((ticket= granted_it++))
2673 {
2674 /* Filter out edges that point to the same node. */
2675 if (ticket->get_ctx() != src_ctx &&
2676 ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
2677 gvisitor->inspect_edge(ticket->get_ctx()))
2678 {
2679 goto end_leave_node;
2680 }
2681 }
2682
2683 while ((ticket= waiting_it++))
2684 {
2685 /* Filter out edges that point to the same node. */
2686 if (ticket->get_ctx() != src_ctx &&
2687 ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
2688 gvisitor->inspect_edge(ticket->get_ctx()))
2689 {
2690 goto end_leave_node;
2691 }
2692 }
2693
2694 /* Recurse and inspect all adjacent nodes. */
2695 granted_it.rewind();
2696 while ((ticket= granted_it++))
2697 {
2698 if (ticket->get_ctx() != src_ctx &&
2699 ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
2700 ticket->get_ctx()->visit_subgraph(gvisitor))
2701 {
2702 goto end_leave_node;
2703 }
2704 }
2705
2706 waiting_it.rewind();
2707 while ((ticket= waiting_it++))
2708 {
2709 if (ticket->get_ctx() != src_ctx &&
2710 ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
2711 ticket->get_ctx()->visit_subgraph(gvisitor))
2712 {
2713 goto end_leave_node;
2714 }
2715 }
2716
2717 result= FALSE;
2718
2719 end_leave_node:
2720 gvisitor->leave_node(src_ctx);
2721
2722 end:
2723 mysql_prlock_unlock(&m_rwlock);
2724 return result;
2725 }
2726
2727
2728 /**
2729 Traverse a portion of wait-for graph which is reachable
2730 through the edge represented by this ticket and search
2731 for deadlocks.
2732
2733 @retval TRUE A deadlock is found. A pointer to deadlock
2734 victim is saved in the visitor.
2735 @retval FALSE
2736 */
2737
accept_visitor(MDL_wait_for_graph_visitor * gvisitor)2738 bool MDL_ticket::accept_visitor(MDL_wait_for_graph_visitor *gvisitor)
2739 {
2740 return m_lock->visit_subgraph(this, gvisitor);
2741 }
2742
2743
2744 /**
2745 A fragment of recursive traversal of the wait-for graph of
2746 MDL contexts in the server in search for deadlocks.
2747 Assume this MDL context is a node in the wait-for graph,
2748 and direct the visitor to all adjacent nodes. As long
2749 as the starting node is remembered in the visitor, a
2750 deadlock is found when the same node is visited twice.
2751 One MDL context is connected to another in the wait-for
2752 graph if it waits on a resource that is held by the other
2753 context.
2754
2755 @retval TRUE A deadlock is found. A pointer to deadlock
2756 victim is saved in the visitor.
2757 @retval FALSE
2758 */
2759
visit_subgraph(MDL_wait_for_graph_visitor * gvisitor)2760 bool MDL_context::visit_subgraph(MDL_wait_for_graph_visitor *gvisitor)
2761 {
2762 bool result= FALSE;
2763
2764 mysql_prlock_rdlock(&m_LOCK_waiting_for);
2765
2766 if (m_waiting_for)
2767 result= m_waiting_for->accept_visitor(gvisitor);
2768
2769 mysql_prlock_unlock(&m_LOCK_waiting_for);
2770
2771 return result;
2772 }
2773
2774
2775 /**
2776 Try to find a deadlock. This function produces no errors.
2777
2778 @note If during deadlock resolution context which performs deadlock
2779 detection is chosen as a victim it will be informed about the
2780 fact by setting VICTIM status to its wait slot.
2781 */
2782
find_deadlock()2783 void MDL_context::find_deadlock()
2784 {
2785 while (1)
2786 {
2787 /*
2788 The fact that we use fresh instance of gvisitor for each
2789 search performed by find_deadlock() below is important,
2790 the code responsible for victim selection relies on this.
2791 */
2792 Deadlock_detection_visitor dvisitor(this);
2793 MDL_context *victim;
2794
2795 if (! visit_subgraph(&dvisitor))
2796 {
2797 /* No deadlocks are found! */
2798 break;
2799 }
2800
2801 victim= dvisitor.get_victim();
2802
2803 /*
2804 Failure to change status of the victim is OK as it means
2805 that the victim has received some other message and is
2806 about to stop its waiting/to break deadlock loop.
2807 Even when the initiator of the deadlock search is
2808 chosen the victim, we need to set the respective wait
2809 result in order to "close" it for any attempt to
2810 schedule the request.
2811 This is needed to avoid a possible race during
2812 cleanup in case when the lock request on which the
2813 context was waiting is concurrently satisfied.
2814 */
2815 (void) victim->m_wait.set_status(MDL_wait::VICTIM);
2816 victim->inc_deadlock_overweight();
2817 victim->unlock_deadlock_victim();
2818
2819 if (victim == this)
2820 break;
2821 /*
2822 After adding a new edge to the waiting graph we found that it
2823 creates a loop (i.e. there is a deadlock). We decided to destroy
2824 this loop by removing an edge, but not the one that we added.
2825 Since this doesn't guarantee that all loops created by addition
2826 of the new edge are destroyed, we have to repeat the search.
2827 */
2828 }
2829 }
2830
2831
2832 /**
2833 Release lock.
2834
2835 @param duration Lock duration.
2836 @param ticket Ticket for lock to be released.
2837
2838 */
2839
release_lock(enum_mdl_duration duration,MDL_ticket * ticket)2840 void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket)
2841 {
2842 MDL_lock *lock= ticket->m_lock;
2843 DBUG_ENTER("MDL_context::release_lock");
2844 DBUG_PRINT("enter", ("db: '%s' name: '%s'",
2845 lock->key.db_name(), lock->key.name()));
2846
2847 DBUG_ASSERT(this == ticket->get_ctx());
2848
2849 lock->remove_ticket(m_pins, &MDL_lock::m_granted, ticket);
2850
2851 m_tickets[duration].remove(ticket);
2852 MDL_ticket::destroy(ticket);
2853
2854 DBUG_VOID_RETURN;
2855 }
2856
2857
2858 /**
2859 Release lock with explicit duration.
2860
2861 @param ticket Ticket for lock to be released.
2862
2863 */
2864
release_lock(MDL_ticket * ticket)2865 void MDL_context::release_lock(MDL_ticket *ticket)
2866 {
2867 DBUG_SLOW_ASSERT(ticket->m_duration == MDL_EXPLICIT);
2868
2869 release_lock(MDL_EXPLICIT, ticket);
2870 }
2871
2872
2873 /**
2874 Release all locks associated with the context. If the sentinel
2875 is not NULL, do not release locks stored in the list after and
2876 including the sentinel.
2877
2878 Statement and transactional locks are added to the beginning of
2879 the corresponding lists, i.e. stored in reverse temporal order.
2880 This allows to employ this function to:
2881 - back off in case of a lock conflict.
2882 - release all locks in the end of a statement or transaction
2883 - rollback to a savepoint.
2884 */
2885
release_locks_stored_before(enum_mdl_duration duration,MDL_ticket * sentinel)2886 void MDL_context::release_locks_stored_before(enum_mdl_duration duration,
2887 MDL_ticket *sentinel)
2888 {
2889 MDL_ticket *ticket;
2890 Ticket_iterator it(m_tickets[duration]);
2891 DBUG_ENTER("MDL_context::release_locks_stored_before");
2892
2893 if (m_tickets[duration].is_empty())
2894 DBUG_VOID_RETURN;
2895
2896 while ((ticket= it++) && ticket != sentinel)
2897 {
2898 DBUG_PRINT("info", ("found lock to release ticket=%p", ticket));
2899 release_lock(duration, ticket);
2900 }
2901
2902 DBUG_VOID_RETURN;
2903 }
2904
2905
2906 /**
2907 Release all explicit locks in the context which correspond to the
2908 same name/object as this lock request.
2909
2910 @param ticket One of the locks for the name/object for which all
2911 locks should be released.
2912 */
2913
release_all_locks_for_name(MDL_ticket * name)2914 void MDL_context::release_all_locks_for_name(MDL_ticket *name)
2915 {
2916 /* Use MDL_ticket::m_lock to identify other locks for the same object. */
2917 MDL_lock *lock= name->m_lock;
2918
2919 /* Remove matching lock tickets from the context. */
2920 MDL_ticket *ticket;
2921 Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
2922
2923 while ((ticket= it_ticket++))
2924 {
2925 DBUG_ASSERT(ticket->m_lock);
2926 if (ticket->m_lock == lock)
2927 release_lock(MDL_EXPLICIT, ticket);
2928 }
2929 }
2930
2931
2932 /**
2933 Downgrade an EXCLUSIVE or SHARED_NO_WRITE lock to shared metadata lock.
2934
2935 @param type Type of lock to which exclusive lock should be downgraded.
2936 */
2937
downgrade_lock(enum_mdl_type type)2938 void MDL_ticket::downgrade_lock(enum_mdl_type type)
2939 {
2940 /*
2941 Do nothing if already downgraded. Used when we FLUSH TABLE under
2942 LOCK TABLES and a table is listed twice in LOCK TABLES list.
2943 Note that this code might even try to "downgrade" a weak lock
2944 (e.g. SW) to a stronger one (e.g SNRW). So we can't even assert
2945 here that target lock is weaker than existing lock.
2946 */
2947 if (m_type == type || !has_stronger_or_equal_type(type))
2948 return;
2949
2950 /* Only allow downgrade in some specific known cases */
2951 DBUG_ASSERT((get_key()->mdl_namespace() != MDL_key::BACKUP &&
2952 (m_type == MDL_EXCLUSIVE ||
2953 m_type == MDL_SHARED_NO_WRITE)) ||
2954 (get_key()->mdl_namespace() == MDL_key::BACKUP &&
2955 (m_type == MDL_BACKUP_DDL ||
2956 m_type == MDL_BACKUP_WAIT_FLUSH)));
2957
2958 mysql_prlock_wrlock(&m_lock->m_rwlock);
2959 /*
2960 To update state of MDL_lock object correctly we need to temporarily
2961 exclude ticket from the granted queue and then include it back.
2962 */
2963 m_lock->m_granted.remove_ticket(this);
2964 m_type= type;
2965 m_lock->m_granted.add_ticket(this);
2966 m_lock->reschedule_waiters();
2967 mysql_prlock_unlock(&m_lock->m_rwlock);
2968 }
2969
2970
2971 /**
2972 Auxiliary function which allows to check if we have some kind of lock on
2973 a object. Returns TRUE if we have a lock of a given or stronger type.
2974
2975 @param mdl_namespace Id of object namespace
2976 @param db Name of the database
2977 @param name Name of the object
2978 @param mdl_type Lock type. Pass in the weakest type to find
2979 out if there is at least some lock.
2980
2981 @return TRUE if current context contains satisfied lock for the object,
2982 FALSE otherwise.
2983 */
2984
2985 bool
is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,const char * db,const char * name,enum_mdl_type mdl_type)2986 MDL_context::is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
2987 const char *db, const char *name,
2988 enum_mdl_type mdl_type)
2989 {
2990 MDL_request mdl_request;
2991 enum_mdl_duration not_unused;
2992 /* We don't care about exact duration of lock here. */
2993 mdl_request.init(mdl_namespace, db, name, mdl_type, MDL_TRANSACTION);
2994 MDL_ticket *ticket= find_ticket(&mdl_request, ¬_unused);
2995
2996 DBUG_ASSERT(ticket == NULL || ticket->m_lock);
2997
2998 return ticket;
2999 }
3000
3001
3002 /**
3003 Return thread id of the owner of the lock or 0 if
3004 there is no owner.
3005 @note: Lock type is not considered at all, the function
3006 simply checks that there is some lock for the given key.
3007
3008 @return thread id of the owner of the lock or 0
3009 */
3010
3011 unsigned long
get_lock_owner(MDL_key * key)3012 MDL_context::get_lock_owner(MDL_key *key)
3013 {
3014 fix_pins();
3015 return mdl_locks.get_lock_owner(m_pins, key);
3016 }
3017
3018
3019 /**
3020 Check if we have any pending locks which conflict with existing shared lock.
3021
3022 @pre The ticket must match an acquired lock.
3023
3024 @return TRUE if there is a conflicting lock request, FALSE otherwise.
3025 */
3026
has_pending_conflicting_lock() const3027 bool MDL_ticket::has_pending_conflicting_lock() const
3028 {
3029 return m_lock->has_pending_conflicting_lock(m_type);
3030 }
3031
3032 /** Return a key identifying this lock. */
get_key() const3033 MDL_key *MDL_ticket::get_key() const
3034 {
3035 return &m_lock->key;
3036 }
3037
3038 /**
3039 Releases metadata locks that were acquired after a specific savepoint.
3040
3041 @note Used to release tickets acquired during a savepoint unit.
3042 @note It's safe to iterate and unlock any locks after taken after this
3043 savepoint because other statements that take other special locks
3044 cause a implicit commit (ie LOCK TABLES).
3045 */
3046
rollback_to_savepoint(const MDL_savepoint & mdl_savepoint)3047 void MDL_context::rollback_to_savepoint(const MDL_savepoint &mdl_savepoint)
3048 {
3049 DBUG_ENTER("MDL_context::rollback_to_savepoint");
3050
3051 /* If savepoint is NULL, it is from the start of the transaction. */
3052 release_locks_stored_before(MDL_STATEMENT, mdl_savepoint.m_stmt_ticket);
3053 release_locks_stored_before(MDL_TRANSACTION, mdl_savepoint.m_trans_ticket);
3054
3055 DBUG_VOID_RETURN;
3056 }
3057
3058
3059 /**
3060 Release locks acquired by normal statements (SELECT, UPDATE,
3061 DELETE, etc) in the course of a transaction. Do not release
3062 HANDLER locks, if there are any.
3063
3064 This method is used at the end of a transaction, in
3065 implementation of COMMIT (implicit or explicit) and ROLLBACK.
3066 */
3067
release_transactional_locks(THD * thd)3068 void MDL_context::release_transactional_locks(THD *thd)
3069 {
3070 DBUG_ENTER("MDL_context::release_transactional_locks");
3071 /* Fail if there are active transactions */
3072 DBUG_ASSERT(!(thd->server_status &
3073 (SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY)));
3074 release_locks_stored_before(MDL_STATEMENT, NULL);
3075 release_locks_stored_before(MDL_TRANSACTION, NULL);
3076 DBUG_VOID_RETURN;
3077 }
3078
release_statement_locks()3079 void MDL_context::release_statement_locks()
3080 {
3081 DBUG_ENTER("MDL_context::release_transactional_locks");
3082 release_locks_stored_before(MDL_STATEMENT, NULL);
3083 DBUG_VOID_RETURN;
3084 }
3085
3086
3087 /**
3088 Does this savepoint have this lock?
3089
3090 @retval TRUE The ticket is older than the savepoint or
3091 is an LT, HA or GLR ticket. Thus it belongs
3092 to the savepoint or has explicit duration.
3093 @retval FALSE The ticket is newer than the savepoint.
3094 and is not an LT, HA or GLR ticket.
3095 */
3096
has_lock(const MDL_savepoint & mdl_savepoint,MDL_ticket * mdl_ticket)3097 bool MDL_context::has_lock(const MDL_savepoint &mdl_savepoint,
3098 MDL_ticket *mdl_ticket)
3099 {
3100 MDL_ticket *ticket;
3101 /* Start from the beginning, most likely mdl_ticket's been just acquired. */
3102 MDL_context::Ticket_iterator s_it(m_tickets[MDL_STATEMENT]);
3103 MDL_context::Ticket_iterator t_it(m_tickets[MDL_TRANSACTION]);
3104
3105 while ((ticket= s_it++) && ticket != mdl_savepoint.m_stmt_ticket)
3106 {
3107 if (ticket == mdl_ticket)
3108 return FALSE;
3109 }
3110
3111 while ((ticket= t_it++) && ticket != mdl_savepoint.m_trans_ticket)
3112 {
3113 if (ticket == mdl_ticket)
3114 return FALSE;
3115 }
3116 return TRUE;
3117 }
3118
3119
3120 /**
3121 Change lock duration for transactional lock.
3122
3123 @param ticket Ticket representing lock.
3124 @param duration Lock duration to be set.
3125
3126 @note This method only supports changing duration of
3127 transactional lock to some other duration.
3128 */
3129
set_lock_duration(MDL_ticket * mdl_ticket,enum_mdl_duration duration)3130 void MDL_context::set_lock_duration(MDL_ticket *mdl_ticket,
3131 enum_mdl_duration duration)
3132 {
3133 DBUG_SLOW_ASSERT(mdl_ticket->m_duration == MDL_TRANSACTION &&
3134 duration != MDL_TRANSACTION);
3135
3136 m_tickets[MDL_TRANSACTION].remove(mdl_ticket);
3137 m_tickets[duration].push_front(mdl_ticket);
3138 #ifndef DBUG_OFF
3139 mdl_ticket->m_duration= duration;
3140 #endif
3141 }
3142
3143
3144 /**
3145 Set explicit duration for all locks in the context.
3146 */
3147
set_explicit_duration_for_all_locks()3148 void MDL_context::set_explicit_duration_for_all_locks()
3149 {
3150 int i;
3151 MDL_ticket *ticket;
3152
3153 /*
3154 In the most common case when this function is called list
3155 of transactional locks is bigger than list of locks with
3156 explicit duration. So we start by swapping these two lists
3157 and then move elements from new list of transactional
3158 locks and list of statement locks to list of locks with
3159 explicit duration.
3160 */
3161
3162 m_tickets[MDL_EXPLICIT].swap(m_tickets[MDL_TRANSACTION]);
3163
3164 for (i= 0; i < MDL_EXPLICIT; i++)
3165 {
3166 Ticket_iterator it_ticket(m_tickets[i]);
3167
3168 while ((ticket= it_ticket++))
3169 {
3170 m_tickets[i].remove(ticket);
3171 m_tickets[MDL_EXPLICIT].push_front(ticket);
3172 }
3173 }
3174
3175 #ifndef DBUG_OFF
3176 Ticket_iterator exp_it(m_tickets[MDL_EXPLICIT]);
3177
3178 while ((ticket= exp_it++))
3179 ticket->m_duration= MDL_EXPLICIT;
3180 #endif
3181 }
3182
3183
3184 /**
3185 Set transactional duration for all locks in the context.
3186 */
3187
set_transaction_duration_for_all_locks()3188 void MDL_context::set_transaction_duration_for_all_locks()
3189 {
3190 MDL_ticket *ticket;
3191
3192 /*
3193 In the most common case when this function is called list
3194 of explicit locks is bigger than two other lists (in fact,
3195 list of statement locks is always empty). So we start by
3196 swapping list of explicit and transactional locks and then
3197 move contents of new list of explicit locks to list of
3198 locks with transactional duration.
3199 */
3200
3201 DBUG_ASSERT(m_tickets[MDL_STATEMENT].is_empty());
3202
3203 m_tickets[MDL_TRANSACTION].swap(m_tickets[MDL_EXPLICIT]);
3204
3205 Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
3206
3207 while ((ticket= it_ticket++))
3208 {
3209 m_tickets[MDL_EXPLICIT].remove(ticket);
3210 m_tickets[MDL_TRANSACTION].push_front(ticket);
3211 }
3212
3213 #ifndef DBUG_OFF
3214 Ticket_iterator trans_it(m_tickets[MDL_TRANSACTION]);
3215
3216 while ((ticket= trans_it++))
3217 ticket->m_duration= MDL_TRANSACTION;
3218 #endif
3219 }
3220
3221
3222
release_explicit_locks()3223 void MDL_context::release_explicit_locks()
3224 {
3225 release_locks_stored_before(MDL_EXPLICIT, NULL);
3226 }
3227
has_explicit_locks()3228 bool MDL_context::has_explicit_locks()
3229 {
3230 MDL_ticket *ticket = NULL;
3231
3232 Ticket_iterator it(m_tickets[MDL_EXPLICIT]);
3233
3234 while ((ticket = it++))
3235 {
3236 return true;
3237 }
3238
3239 return false;
3240 }
3241
3242 #ifdef WITH_WSREP
3243 static
wsrep_get_mdl_namespace_name(MDL_key::enum_mdl_namespace ns)3244 const char *wsrep_get_mdl_namespace_name(MDL_key::enum_mdl_namespace ns)
3245 {
3246 switch (ns)
3247 {
3248 case MDL_key::BACKUP : return "BACKUP";
3249 case MDL_key::SCHEMA : return "SCHEMA";
3250 case MDL_key::TABLE : return "TABLE";
3251 case MDL_key::FUNCTION : return "FUNCTION";
3252 case MDL_key::PROCEDURE : return "PROCEDURE";
3253 case MDL_key::PACKAGE_BODY: return "PACKAGE BODY";
3254 case MDL_key::TRIGGER : return "TRIGGER";
3255 case MDL_key::EVENT : return "EVENT";
3256 case MDL_key::USER_LOCK : return "USER_LOCK";
3257 default: break;
3258 }
3259 return "UNKNOWN";
3260 }
3261
wsrep_report(bool debug)3262 void MDL_ticket::wsrep_report(bool debug)
3263 {
3264 if (!debug) return;
3265
3266 const PSI_stage_info *psi_stage= m_lock->key.get_wait_state_name();
3267 WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s (%s)",
3268 get_type_name()->str,
3269 wsrep_get_mdl_namespace_name(m_lock->key.mdl_namespace()),
3270 m_lock->key.db_name(),
3271 m_lock->key.name(),
3272 psi_stage->m_name);
3273 }
3274 #endif /* WITH_WSREP */
3275