1 /* Copyright (c) 2007, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23
24 #include "mdl.h"
25 #include "debug_sync.h"
26 #include "prealloced_array.h"
27 #include <lf.h>
28 #include "mysqld.h"
29 #include <mysqld_error.h>
30 #include <mysql/plugin.h>
31 #include <mysql/service_thd_wait.h>
32 #include <pfs_metadata_provider.h>
33 #include <mysql/psi/mysql_mdl.h>
34 #include <pfs_stage_provider.h>
35 #include <mysql/psi/mysql_stage.h>
36 #include <my_murmur3.h>
37 #include <algorithm>
38 #include <functional>
39
40 static PSI_memory_key key_memory_MDL_context_acquire_locks;
41
42 #ifdef HAVE_PSI_INTERFACE
43 static PSI_mutex_key key_MDL_wait_LOCK_wait_status;
44
45 static PSI_mutex_info all_mdl_mutexes[]=
46 {
47 { &key_MDL_wait_LOCK_wait_status, "MDL_wait::LOCK_wait_status", 0}
48 };
49
50 static PSI_rwlock_key key_MDL_lock_rwlock;
51 static PSI_rwlock_key key_MDL_context_LOCK_waiting_for;
52
53 static PSI_rwlock_info all_mdl_rwlocks[]=
54 {
55 { &key_MDL_lock_rwlock, "MDL_lock::rwlock", 0},
56 { &key_MDL_context_LOCK_waiting_for, "MDL_context::LOCK_waiting_for", 0}
57 };
58
59 static PSI_cond_key key_MDL_wait_COND_wait_status;
60
61 static PSI_cond_info all_mdl_conds[]=
62 {
63 { &key_MDL_wait_COND_wait_status, "MDL_context::COND_wait_status", 0}
64 };
65
66 static PSI_memory_info all_mdl_memory[]=
67 {
68 { &key_memory_MDL_context_acquire_locks, "MDL_context::acquire_locks", 0}
69 };
70
71 /**
72 Initialise all the performance schema instrumentation points
73 used by the MDL subsystem.
74 */
init_mdl_psi_keys(void)75 static void init_mdl_psi_keys(void)
76 {
77 int count;
78
79 count= array_elements(all_mdl_mutexes);
80 mysql_mutex_register("sql", all_mdl_mutexes, count);
81
82 count= array_elements(all_mdl_rwlocks);
83 mysql_rwlock_register("sql", all_mdl_rwlocks, count);
84
85 count= array_elements(all_mdl_conds);
86 mysql_cond_register("sql", all_mdl_conds, count);
87
88 count= array_elements(all_mdl_memory);
89 mysql_memory_register("sql", all_mdl_memory, count);
90
91 MDL_key::init_psi_keys();
92 }
93 #endif /* HAVE_PSI_INTERFACE */
94
95
96 /**
97 Thread state names to be used in case when we have to wait on resource
98 belonging to certain namespace.
99 */
100
101 PSI_stage_info MDL_key::m_namespace_to_wait_state_name[NAMESPACE_END]=
102 {
103 {0, "Waiting for global read lock", 0},
104 {0, "Waiting for tablespace metadata lock", 0},
105 {0, "Waiting for schema metadata lock", 0},
106 {0, "Waiting for table metadata lock", 0},
107 {0, "Waiting for stored function metadata lock", 0},
108 {0, "Waiting for stored procedure metadata lock", 0},
109 {0, "Waiting for trigger metadata lock", 0},
110 {0, "Waiting for event metadata lock", 0},
111 {0, "Waiting for commit lock", 0},
112 {0, "User lock", 0}, /* Be compatible with old status. */
113 {0, "Waiting for locking service lock", 0},
114 {0, "Waiting for backup lock", 0},
115 {0, "Waiting for binlog lock", 0}
116 };
117
118 #ifdef HAVE_PSI_INTERFACE
init_psi_keys()119 void MDL_key::init_psi_keys()
120 {
121 int i;
122 int count;
123 PSI_stage_info *info MY_ATTRIBUTE((unused));
124
125 count= array_elements(MDL_key::m_namespace_to_wait_state_name);
126 for (i= 0; i<count; i++)
127 {
128 /* mysql_stage_register wants an array of pointers, registering 1 by 1. */
129 info= & MDL_key::m_namespace_to_wait_state_name[i];
130 mysql_stage_register("sql", &info, 1);
131 }
132 }
133 #endif
134
135 static bool mdl_initialized= 0;
136
137
138 /**
139 A collection of all MDL locks. A singleton,
140 there is only one instance of the map in the server.
141 */
142
143 class MDL_map
144 {
145 public:
146 void init();
147 void destroy();
148
149 inline MDL_lock *find(LF_PINS *pins, const MDL_key *key, bool *pinned);
150 inline MDL_lock *find_or_insert(LF_PINS *pins, const MDL_key *key, bool *pinned);
151
152 /**
153 Decrement unused MDL_lock objects counter.
154 */
lock_object_used()155 void lock_object_used()
156 {
157 my_atomic_add32(&m_unused_lock_objects, -1);
158 }
159
160 /**
161 Increment unused MDL_lock objects counter. If number of such objects
162 exceeds threshold and unused/total objects ratio is high enough try
163 to free some of them.
164 */
lock_object_unused(MDL_context * ctx,LF_PINS * pins)165 void lock_object_unused(MDL_context *ctx, LF_PINS *pins)
166 {
167 /*
168 Use thread local copy of unused locks counter for performance/
169 scalability reasons. It is updated on both successfull and failed
170 attempts to delete unused MDL_lock objects in order to avoid infinite
171 loops,
172 */
173 int32 unused_locks= my_atomic_add32(&m_unused_lock_objects, 1) + 1;
174
175 while (unused_locks > mdl_locks_unused_locks_low_water &&
176 (unused_locks > m_locks.count * MDL_LOCKS_UNUSED_LOCKS_MIN_RATIO))
177 {
178 /*
179 If number of unused lock objects exceeds low water threshold and
180 unused/total objects ratio is high enough - try to do random dive
181 into m_locks hash, find an unused object by iterating upwards
182 through its split-ordered list and try to free it.
183 If we fail to do this - update local copy of unused objects
184 counter and retry if needed,
185
186 Note that:
187 *) It is not big deal if "m_unused_lock_objects" due to races becomes
188 negative temporarily as we perform signed comparison.
189 *) There is a good chance that we will find an unused object quickly
190 because unused/total ratio is high enough.
191 *) There is no possibility for infinite loop since our PRNG works
192 in such way that we eventually cycle through all LF_HASH hash
193 buckets (@sa MDL_context::get_random()).
194 *) Thanks to the fact that we choose random object to expel -
195 objects which are used more often will naturally stay
196 in the cache and rarely used objects will be expelled from it.
197 *) Non-atomic read of LF_HASH::count which happens above should be
198 OK as LF_HASH code does them too + preceding atomic operation
199 provides memory barrier.
200 */
201 remove_random_unused(ctx, pins, &unused_locks);
202 }
203 }
204
205 /**
206 Get number of unused MDL_lock objects in MDL_map cache.
207
208 @note Does non-atomic read so can return stale results. This is OK since
209 this method is used only in unit-tests. The latter employ means
210 of thread synchronization which are external to MDL and prevent
211 memory reordering/ensure that thread calling this method have
212 up-to-date view on the memory. @sa m_unused_lock_objects.
213 */
get_unused_locks_count() const214 int32 get_unused_locks_count() const
215 {
216 return m_unused_lock_objects;
217 }
218
219 /**
220 Allocate pins which are necessary for MDL_context/thread to be able
221 to work with MDL_map container.
222 */
get_pins()223 LF_PINS *get_pins() { return lf_hash_get_pins(&m_locks); }
224
225 /**
226 Check if MDL_lock object corresponding to the key is going to be
227 singleton.
228 */
is_lock_object_singleton(const MDL_key * mdl_key) const229 bool is_lock_object_singleton(const MDL_key *mdl_key) const
230 {
231 return (mdl_key->mdl_namespace() == MDL_key::GLOBAL ||
232 mdl_key->mdl_namespace() == MDL_key::COMMIT ||
233 mdl_key->mdl_namespace() == MDL_key::BACKUP ||
234 mdl_key->mdl_namespace() == MDL_key::BINLOG);
235 }
236
237 private:
238
239 void remove_random_unused(MDL_context *ctx, LF_PINS *pins, int32 *unused_locks);
240
241 /** LF_HASH with all locks in the server. */
242 LF_HASH m_locks;
243 /** Pre-allocated MDL_lock object for GLOBAL namespace. */
244 MDL_lock *m_global_lock;
245 /** Pre-allocated MDL_lock object for COMMIT namespace. */
246 MDL_lock *m_commit_lock;
247 /**
248 Number of unused MDL_lock objects in the server.
249
250 Updated using atomic operations, read using both atomic and ordinary
251 reads. We assume that ordinary reads of 32-bit words can't result in
252 partial results, but may produce stale results thanks to memory
253 reordering, LF_HASH seems to be using similar assumption.
254
255 Note that due to fact that updates to this counter are not atomic with
256 marking MDL_lock objects as used/unused it might easily get negative
257 for some short period of time. Code which uses its value needs to take
258 this into account.
259 */
260 volatile int32 m_unused_lock_objects;
261 /** Pre-allocated MDL_lock object for BACKUP namespace. */
262 MDL_lock *m_backup_lock;
263 /** Pre-allocated MDL_lock object for BINLOG namespace */
264 MDL_lock *m_binlog_lock;
265 };
266
267
268 /**
269 Threshold for number of unused MDL_lock objects.
270
271 We will start considering freeing some unused objects only after exceeding
272 this value and if unused/total objects ratio is high enough.
273
274 Normally this threshold is constant. It is exposed outside of MDL subsystem
275 as a variable only in order to simplify unit testing.
276 */
277 int32 mdl_locks_unused_locks_low_water=
278 MDL_LOCKS_UNUSED_LOCKS_LOW_WATER_DEFAULT;
279
280
281 /**
282 A context of the recursive traversal through all contexts
283 in all sessions in search for deadlock.
284 */
285
286 class Deadlock_detection_visitor: public MDL_wait_for_graph_visitor
287 {
288 public:
Deadlock_detection_visitor(MDL_context * start_node_arg)289 Deadlock_detection_visitor(MDL_context *start_node_arg)
290 : m_start_node(start_node_arg),
291 m_victim(NULL),
292 m_current_search_depth(0),
293 m_found_deadlock(FALSE)
294 {}
295 virtual bool enter_node(MDL_context *node);
296 virtual void leave_node(MDL_context *node);
297
298 virtual bool inspect_edge(MDL_context *dest);
299
get_victim() const300 MDL_context *get_victim() const { return m_victim; }
301 private:
302 /**
303 Change the deadlock victim to a new one if it has lower deadlock
304 weight.
305 */
306 void opt_change_victim_to(MDL_context *new_victim);
307 private:
308 /**
309 The context which has initiated the search. There
310 can be multiple searches happening in parallel at the same time.
311 */
312 MDL_context *m_start_node;
313 /** If a deadlock is found, the context that identifies the victim. */
314 MDL_context *m_victim;
315 /** Set to the 0 at start. Increased whenever
316 we descend into another MDL context (aka traverse to the next
317 wait-for graph node). When MAX_SEARCH_DEPTH is reached, we
318 assume that a deadlock is found, even if we have not found a
319 loop.
320 */
321 uint m_current_search_depth;
322 /** TRUE if we found a deadlock. */
323 bool m_found_deadlock;
324 /**
325 Maximum depth for deadlock searches. After this depth is
326 achieved we will unconditionally declare that there is a
327 deadlock.
328
329 @note This depth should be small enough to avoid stack
330 being exhausted by recursive search algorithm.
331
332 TODO: Find out what is the optimal value for this parameter.
333 Current value is safe, but probably sub-optimal,
334 as there is an anecdotal evidence that real-life
335 deadlocks are even shorter typically.
336 */
337 static const uint MAX_SEARCH_DEPTH= 32;
338 };
339
340
341 /**
342 Enter a node of a wait-for graph. After
343 a node is entered, inspect_edge() will be called
344 for all wait-for destinations of this node. Then
345 leave_node() will be called.
346 We call "enter_node()" for all nodes we inspect,
347 including the starting node.
348
349 @retval TRUE Maximum search depth exceeded.
350 @retval FALSE OK.
351 */
352
enter_node(MDL_context * node)353 bool Deadlock_detection_visitor::enter_node(MDL_context *node)
354 {
355 m_found_deadlock= ++m_current_search_depth >= MAX_SEARCH_DEPTH;
356 if (m_found_deadlock)
357 {
358 assert(! m_victim);
359 opt_change_victim_to(node);
360 }
361 return m_found_deadlock;
362 }
363
364
365 /**
366 Done inspecting this node. Decrease the search
367 depth. If a deadlock is found, and we are
368 backtracking to the start node, optionally
369 change the deadlock victim to one with lower
370 deadlock weight.
371 */
372
leave_node(MDL_context * node)373 void Deadlock_detection_visitor::leave_node(MDL_context *node)
374 {
375 --m_current_search_depth;
376 if (m_found_deadlock)
377 opt_change_victim_to(node);
378 }
379
380
381 /**
382 Inspect a wait-for graph edge from one MDL context to another.
383
384 @retval TRUE A loop is found.
385 @retval FALSE No loop is found.
386 */
387
inspect_edge(MDL_context * node)388 bool Deadlock_detection_visitor::inspect_edge(MDL_context *node)
389 {
390 m_found_deadlock= node == m_start_node;
391 return m_found_deadlock;
392 }
393
394
395 /**
396 Change the deadlock victim to a new one if it has lower deadlock
397 weight.
398
399 @param new_victim New candidate for deadlock victim.
400 */
401
402 void
opt_change_victim_to(MDL_context * new_victim)403 Deadlock_detection_visitor::opt_change_victim_to(MDL_context *new_victim)
404 {
405 if (m_victim == NULL ||
406 m_victim->get_deadlock_weight() >= new_victim->get_deadlock_weight())
407 {
408 /* Swap victims, unlock the old one. */
409 MDL_context *tmp= m_victim;
410 m_victim= new_victim;
411 m_victim->lock_deadlock_victim();
412 if (tmp)
413 tmp->unlock_deadlock_victim();
414 }
415 }
416
417
418 /**
419 Get a bit corresponding to enum_mdl_type value in a granted/waiting bitmaps
420 and compatibility matrices.
421 */
422
423 #define MDL_BIT(A) static_cast<MDL_lock::bitmap_t>(1U << A)
424
425 /**
426 The lock context. Created internally for an acquired lock.
427 For a given name, there exists only one MDL_lock instance,
428 and it exists only when the lock has been granted.
429 Can be seen as an MDL subsystem's version of TABLE_SHARE.
430
431 This is an abstract class which lacks information about
432 compatibility rules for lock types. They should be specified
433 in its descendants.
434 */
435
436 class MDL_lock
437 {
438 public:
439 typedef unsigned short bitmap_t;
440
441 class Ticket_list
442 {
443 public:
444 typedef I_P_List<MDL_ticket,
445 I_P_List_adapter<MDL_ticket,
446 &MDL_ticket::next_in_lock,
447 &MDL_ticket::prev_in_lock>,
448 I_P_List_null_counter,
449 I_P_List_fast_push_back<MDL_ticket> >
450 List;
operator const List&() const451 operator const List &() const { return m_list; }
Ticket_list()452 Ticket_list() :m_bitmap(0) {}
453
454 void add_ticket(MDL_ticket *ticket);
455 void remove_ticket(MDL_ticket *ticket);
is_empty() const456 bool is_empty() const { return m_list.is_empty(); }
bitmap() const457 bitmap_t bitmap() const { return m_bitmap; }
458 private:
459 void clear_bit_if_not_in_list(enum_mdl_type type);
460 private:
461 /** List of tickets. */
462 List m_list;
463 /** Bitmap of types of tickets in this list. */
464 bitmap_t m_bitmap;
465 };
466
467 typedef Ticket_list::List::Iterator Ticket_iterator;
468
469 typedef longlong fast_path_state_t;
470
471 /**
472 Helper struct which defines how different types of locks are handled
473 for a specific MDL_lock. In practice we use only two strategies: "scoped"
474 lock strategy for locks in GLOBAL, COMMIT, TABLESPACE and SCHEMA namespaces
475 and "object" lock strategy for all other namespaces.
476 */
477 struct MDL_lock_strategy
478 {
479 /**
480 Compatibility (or rather "incompatibility") matrices for lock types.
481
482 Array of bitmaps which elements specify which granted locks are
483 incompatible with the type of lock being requested.
484 */
485 bitmap_t m_granted_incompatible[MDL_TYPE_END];
486 /**
487 Arrays of bitmaps which elements specify which waiting locks are
488 incompatible with the type of lock being requested. Basically, each
489 array defines priorities between lock types.
490 We need 4 separate arrays since in order to prevent starvation for
491 some of lock request types, we use different priority matrices:
492 0) in "normal" situation.
493 1) in situation when the number of successively granted "piglet" requests
494 exceeds the max_write_lock_count limit.
495 2) in situation when the number of successively granted "hog" requests
496 exceeds the max_write_lock_count limit.
497 3) in situation when both "piglet" and "hog" counters exceed limit.
498 */
499 bitmap_t m_waiting_incompatible[4][MDL_TYPE_END];
500 /**
501 Array of increments for "unobtrusive" types of lock requests for locks.
502 @sa MDL_lock::get_unobtrusive_lock_increment().
503 */
504 fast_path_state_t m_unobtrusive_lock_increment[MDL_TYPE_END];
505 /**
506 Indicates that locks of this type are affected by
507 the max_write_lock_count limit.
508 */
509 bool m_is_affected_by_max_write_lock_count;
510
511 /**
512 Pointer to a static method which determines if the type of lock
513 requested requires notification of conflicting locks. NULL if there
514 are no lock types requiring notification.
515 */
516 bool (*m_needs_notification)(const MDL_ticket *ticket);
517 /**
518 Pointer to a static method which allows notification of owners of
519 conflicting locks about the fact that a type of lock requiring
520 notification was requested.
521 */
522 void (*m_notify_conflicting_locks)(MDL_context *ctx, MDL_lock *lock);
523 /**
524 Pointer to a static method which converts information about
525 locks granted using "fast" path from fast_path_state_t
526 representation to bitmap of lock types.
527 */
528 bitmap_t (*m_fast_path_granted_bitmap)(const MDL_lock &lock);
529 /**
530 Pointer to a static method which determines if waiting for the lock
531 should be aborted when when connection is lost. NULL if locks of
532 this type don't require such aborts.
533 */
534 bool (*m_needs_connection_check)(const MDL_lock *lock);
535 };
536
537 public:
538 /** The key of the object (data) being protected. */
539 MDL_key key;
540 /**
541 Read-write lock protecting this lock context.
542
543 @note The fact that we use read-write lock prefers readers here is
544 important as deadlock detector won't work correctly otherwise.
545
546 For example, imagine that we have following waiters graph:
547
548 ctxA -> obj1 -> ctxB -> obj1 -|
549 ^ |
550 |----------------------------|
551
552 and both ctxA and ctxB start deadlock detection process:
553
554 ctxA read-locks obj1 ctxB read-locks obj2
555 ctxA goes deeper ctxB goes deeper
556
557 Now ctxC comes in who wants to start waiting on obj1, also
558 ctxD comes in who wants to start waiting on obj2.
559
560 ctxC tries to write-lock obj1 ctxD tries to write-lock obj2
561 ctxC is blocked ctxD is blocked
562
563 Now ctxA and ctxB resume their search:
564
565 ctxA tries to read-lock obj2 ctxB tries to read-lock obj1
566
567 If m_rwlock prefers writes (or fair) both ctxA and ctxB would be
568 blocked because of pending write locks from ctxD and ctxC
569 correspondingly. Thus we will get a deadlock in deadlock detector.
570 If m_wrlock prefers readers (actually ignoring pending writers is
571 enough) ctxA and ctxB will continue and no deadlock will occur.
572 */
573 mysql_prlock_t m_rwlock;
574
incompatible_granted_types_bitmap() const575 const bitmap_t *incompatible_granted_types_bitmap() const
576 {
577 return m_strategy->m_granted_incompatible;
578 }
579
incompatible_waiting_types_bitmap() const580 const bitmap_t *incompatible_waiting_types_bitmap() const
581 {
582 return
583 m_strategy->m_waiting_incompatible[m_current_waiting_incompatible_idx];
584 }
585
586 /**
587 Get index of priority matrice in MDL_lock_strategy::m_waiting_incompatible
588 array which corresponds to current values of the m_piglet_lock_count and
589 m_hog_lock_count counters and the max_write_lock_count threshold.
590 */
get_incompatible_waiting_types_bitmap_idx() const591 uint get_incompatible_waiting_types_bitmap_idx() const
592 {
593 mysql_prlock_assert_write_owner(&m_rwlock);
594 /*
595 To prevent starvation for lock types with lower priority use:
596
597 *) MDL_lock_strategy::m_waiting_incompatible[0] matrice by default.
598 *) MDL_lock_strategy::m_waiting_incompatible[1] when the number of
599 successively granted "piglet" requests exceeds max_write_lock_count.
600 *) MDL_lock_strategy::m_waiting_incompatible[2] when the number of
601 successively granted "hog" requests exceeds max_write_lock_count.
602 *) MDL_lock_strategy::m_waiting_incompatible[3] when both "piglet" and
603 "hog" counters exceed this limit.
604 */
605 uint idx= 0;
606 if (m_piglet_lock_count >= max_write_lock_count)
607 idx+= 1;
608 if (m_hog_lock_count >= max_write_lock_count)
609 idx+= 2;
610 return idx;
611 }
612
613 /**
614 Switch priority matrice for the MDL_lock object if m_piglet_lock_count or/
615 and m_hog_lock_count counters have crossed max_write_lock_count threshold.
616
617 @returns true - if priority matrice has been changed, false - otherwise.
618 */
switch_incompatible_waiting_types_bitmap_if_needed()619 bool switch_incompatible_waiting_types_bitmap_if_needed()
620 {
621 mysql_prlock_assert_write_owner(&m_rwlock);
622
623 uint new_idx= get_incompatible_waiting_types_bitmap_idx();
624 if (m_current_waiting_incompatible_idx == new_idx)
625 return false;
626 m_current_waiting_incompatible_idx= new_idx;
627 return true;
628 }
629
630 bool has_pending_conflicting_lock(enum_mdl_type type);
631
632 bool can_grant_lock(enum_mdl_type type,
633 const MDL_context *requestor_ctx) const;
634
635 void reschedule_waiters();
636
637 void remove_ticket(MDL_context *ctx, LF_PINS *pins,
638 Ticket_list MDL_lock::*queue,
639 MDL_ticket *ticket);
640
641 bool visit_subgraph(MDL_ticket *waiting_ticket,
642 MDL_wait_for_graph_visitor *gvisitor);
643
needs_notification(const MDL_ticket * ticket) const644 bool needs_notification(const MDL_ticket *ticket) const
645 {
646 return m_strategy->m_needs_notification ?
647 m_strategy->m_needs_notification(ticket) : false;
648 }
649
notify_conflicting_locks(MDL_context * ctx)650 void notify_conflicting_locks(MDL_context *ctx)
651 {
652 if (m_strategy->m_notify_conflicting_locks)
653 m_strategy->m_notify_conflicting_locks(ctx, this);
654 }
655
needs_connection_check() const656 bool needs_connection_check() const
657 {
658 return m_strategy->m_needs_connection_check ?
659 m_strategy->m_needs_connection_check(this) : false;
660 }
661
662 inline static bool needs_hton_notification(MDL_key::enum_mdl_namespace
663 mdl_namespace);
664
is_affected_by_max_write_lock_count() const665 bool is_affected_by_max_write_lock_count() const
666 {
667 return m_strategy->m_is_affected_by_max_write_lock_count;
668 }
669
670 /**
671 If we just have granted a lock of "piglet" or "hog" type and there are
672 pending lower priority locks, increase the appropriate counter. If this
673 counter now exceeds the max_write_lock_count threshold, switch priority
674 matrice for the MDL_lock object.
675
676 @returns true - if priority matrice has been changed, false - otherwise.
677 */
count_piglets_and_hogs(enum_mdl_type type)678 bool count_piglets_and_hogs(enum_mdl_type type)
679 {
680 mysql_prlock_assert_write_owner(&m_rwlock);
681
682 if ((MDL_BIT(type) & MDL_OBJECT_HOG_LOCK_TYPES) != 0)
683 {
684 if (m_waiting.bitmap() & ~MDL_OBJECT_HOG_LOCK_TYPES)
685 {
686 m_hog_lock_count++;
687 if (switch_incompatible_waiting_types_bitmap_if_needed())
688 return true;
689 }
690 }
691 else if (type == MDL_SHARED_WRITE)
692 {
693 if (m_waiting.bitmap() & MDL_BIT(MDL_SHARED_READ_ONLY))
694 {
695 m_piglet_lock_count++;
696 if (switch_incompatible_waiting_types_bitmap_if_needed())
697 return true;
698 }
699 }
700 return false;
701 }
702
703 /**
704 @returns "Fast path" increment for request for "unobtrusive" type
705 of lock, 0 - if it is request for "obtrusive" type of
706 lock.
707
708 @note We split all lock types for each of MDL namespaces
709 in two sets:
710
711 A) "unobtrusive" lock types
712 1) Each type from this set should be compatible with all other
713 types from the set (including itself).
714 2) These types should be common for DML operations
715
716 Our goal is to optimize acquisition and release of locks of this
717 type by avoiding complex checks and manipulations on m_waiting/
718 m_granted bitmaps/lists. We replace them with a check of and
719 increment/decrement of integer counters.
720 We call the latter type of acquisition/release "fast path".
721 Use of "fast path" reduces the size of critical section associated
722 with MDL_lock::m_rwlock lock in the common case and thus increases
723 scalability.
724
725 The amount by which acquisition/release of specific type
726 "unobtrusive" lock increases/decreases packed counter in
727 MDL_lock::m_fast_path_state is returned by this function.
728
729 B) "obtrusive" lock types
730 1) Granted or pending lock of those type is incompatible with
731 some other types of locks or with itself.
732 2) Not common for DML operations
733
734 These locks have to be always acquired involving manipulations on
735 m_waiting/m_granted bitmaps/lists, i.e. we have to use "slow path"
736 for them. Moreover in the presence of active/pending locks from
737 "obtrusive" set we have to acquire using "slow path" even locks of
738 "unobtrusive" type.
739
740 @sa MDL_scoped_lock/MDL_object_lock::m_unobtrusive_lock_increment for
741 definitions of these sets for scoped and per-object locks.
742 */
743 inline static fast_path_state_t
744 get_unobtrusive_lock_increment(const MDL_request *request);
745
746 /**
747 @returns "Fast path" increment if type of lock is "unobtrusive" type,
748 0 - if it is "obtrusive" type of lock.
749 */
get_unobtrusive_lock_increment(enum_mdl_type type) const750 fast_path_state_t get_unobtrusive_lock_increment(enum_mdl_type type) const
751 {
752 return m_strategy->m_unobtrusive_lock_increment[type];
753 }
754
755 /**
756 Check if type of lock requested is "obtrusive" type of lock.
757
758 @sa MDL_lock::get_unobtrusive_lock_increment() description.
759 */
is_obtrusive_lock(enum_mdl_type type) const760 bool is_obtrusive_lock(enum_mdl_type type) const
761 {
762 return get_unobtrusive_lock_increment(type) == 0;
763 }
764
765 /**
766 Return set of types of lock requests which were granted using
767 "fast path" algorithm in the bitmap_t form.
768
769 This method is only called from MDL_lock::can_grant_lock() and its
770 return value is only important when we are trying to figure out if
771 we can grant an obtrusive lock. But this means that the HAS_OBTRUSIVE
772 flag is set so all changes to m_fast_path_state happen under protection
773 of MDL_lock::m_rwlock (see invariant [INV1]).
774 Since can_grant_lock() is called only when MDL_lock::m_rwlock is held,
775 it is safe to do an ordinary read of m_fast_path_state here.
776 */
fast_path_granted_bitmap() const777 bitmap_t fast_path_granted_bitmap() const
778 {
779 return m_strategy->m_fast_path_granted_bitmap(*this);
780 }
781
782 /** List of granted tickets for this lock. */
783 Ticket_list m_granted;
784 /** Tickets for contexts waiting to acquire a lock. */
785 Ticket_list m_waiting;
786
787 private:
788 /**
789 Number of times high priority, "hog" lock requests (X, SNRW, SNW) have been
790 granted while lower priority lock requests (all other types) were waiting.
791 Currently used only for object locks. Protected by m_rwlock lock.
792 */
793 ulong m_hog_lock_count;
794 /**
795 Number of times high priority, "piglet" lock requests (SW) have been
796 granted while locks requests with lower priority (SRO) were waiting.
797 Currently used only for object locks. Protected by m_rwlock lock.
798 */
799 ulong m_piglet_lock_count;
800 /**
801 Index of one of the MDL_lock_strategy::m_waiting_incompatible
802 arrays which represents the current priority matrice.
803 */
804 uint m_current_waiting_incompatible_idx;
805
806 public:
807
808 /**
809 Do "expensive" part of MDL_lock object initialization,
810 Called by LF_ALLOCATOR for each newly malloc()'ed MDL_lock object, is not
811 called in cases when LF_ALLOCATOR decides to reuse object which was
812 returned to it earlier. "Full" initialization happens later by calling
813 MDL_lock::reinit(). So @sa MDL_lock::reiniti()
814 */
MDL_lock()815 MDL_lock()
816 : m_obtrusive_locks_granted_waiting_count(0)
817 {
818 mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock);
819 }
820
821 inline void reinit(const MDL_key *mdl_key);
822
~MDL_lock()823 ~MDL_lock()
824 {
825 mysql_prlock_destroy(&m_rwlock);
826 }
827
828 inline static MDL_lock *create(const MDL_key *key);
829 inline static void destroy(MDL_lock *lock);
830
831 inline MDL_context *get_lock_owner() const;
832
833 public:
834 /**
835 Number of granted or waiting lock requests of "obtrusive" type.
836 Also includes "obtrusive" lock requests for which we about to check
837 if they can be granted.
838
839
840 @sa MDL_lock::get_unobtrusive_lock_increment() description.
841
842 @note This number doesn't include "unobtrusive" locks which were acquired
843 using "slow path".
844 */
845 uint m_obtrusive_locks_granted_waiting_count;
846 /**
847 Flag in MDL_lock::m_fast_path_state that indicates that the MDL_lock
848 object was marked for destruction and will be destroyed once all threads
849 referencing to it through hazard pointers have unpinned it.
850 Set using atomic compare-and-swap AND under protection of
851 MDL_lock::m_rwlock lock.
852 Thanks to this can be read either by using atomic compare-and-swap OR
853 using ordinary read under protection of MDL_lock::m_rwlock lock.
854 */
855 static const fast_path_state_t IS_DESTROYED= 1ULL << 62;
856 /**
857 Flag in MDL_lock::m_fast_path_state that indicates that there are
858 "obtrusive" locks which are granted, waiting or for which we are
859 about to check if they can be granted.
860 Corresponds to "MDL_lock::m_obtrusive_locks_granted_waiting_count == 0"
861 predicate.
862 Set using atomic compare-and-swap AND under protection of
863 MDL_lock::m_rwlock lock.
864 Thanks to this can be read either by using atomic compare-and-swap OR
865 using ordinary read under protection of MDL_lock::m_rwlock lock.
866
867 Invariant [INV1]: When this flag is set all changes to m_fast_path_state
868 member has to be done under protection of m_rwlock lock.
869 */
870 static const fast_path_state_t HAS_OBTRUSIVE= 1ULL << 61;
871 /**
872 Flag in MDL_lock::m_fast_path_state that indicates that there are
873 "slow" path locks which are granted, waiting or for which we are
874 about to check if they can be granted.
875 Corresponds to MDL_lock::m_granted/m_waiting lists being non-empty
876 (except special case in MDL_context::try_acquire_lock()).
877 Set using atomic compare-and-swap AND under protection of m_rwlock
878 lock. The latter is necessary because value of this flag needs to be
879 synchronized with contents of MDL_lock::m_granted/m_waiting lists.
880 */
881 static const fast_path_state_t HAS_SLOW_PATH= 1ULL << 60;
882 /**
883 Combination of IS_DESTROYED/HAS_OBTRUSIVE/HAS_SLOW_PATH flags and packed
884 counters of specific types of "unobtrusive" locks which were granted using
885 "fast path".
886
887 @sa MDL_scoped_lock::m_unobtrusive_lock_increment and
888 MDL_object_lock::m_unobtrusive_lock_increment for details about how
889 counts of different types of locks are packed into this field.
890
891 @note Doesn't include "unobtrusive" locks granted using "slow path".
892
893 @note We use combination of atomic operations and protection by
894 MDL_lock::m_rwlock lock to work with this member:
895
896 * Write and Read-Modify-Write operations are always carried out
897 atomically. This is necessary to avoid lost updates on 32-bit
898 platforms among other things.
899 * In some cases Reads can be done non-atomically because we don't
900 really care about value which they will return (for example,
901 if further down the line there will be an atomic compare-and-swap
902 operation, which will validate this value and provide the correct
903 value if the validation will fail).
904 * In other cases Reads can be done non-atomically since they happen
905 under protection of MDL_lock::m_rwlock and there is some invariant
906 which ensures that concurrent updates of the m_fast_path_state
907 member can't happen while MDL_lock::m_rwlock is held
908 (@sa IS_DESTROYED, HAS_OBTRUSIVE, HAS_SLOW_PATH).
909
910 @note IMPORTANT!!!
911 In order to enforce the above rules and other invariants,
912 MDL_lock::m_fast_path_state should not be updated directly.
913 Use fast_path_state_cas()/add()/reset() wrapper methods instead.
914
915 @note Needs to be volatile in order to be compatible with our
916 my_atomic_*() API.
917 */
918 volatile fast_path_state_t m_fast_path_state;
919
920 /**
921 Wrapper for my_atomic_cas64 operation on m_fast_path_state member
922 which enforces locking and other invariants.
923 */
fast_path_state_cas(fast_path_state_t * old_state,fast_path_state_t new_state)924 bool fast_path_state_cas(fast_path_state_t *old_state,
925 fast_path_state_t new_state)
926 {
927 /*
928 IS_DESTROYED, HAS_OBTRUSIVE and HAS_SLOW_PATH flags can be set or
929 cleared only while holding MDL_lock::m_rwlock lock.
930 If HAS_SLOW_PATH flag is set all changes to m_fast_path_state
931 should happen under protection of MDL_lock::m_rwlock ([INV1]).
932 */
933 #if !defined(NDEBUG)
934 if (((*old_state & (IS_DESTROYED | HAS_OBTRUSIVE | HAS_SLOW_PATH)) !=
935 (new_state & (IS_DESTROYED | HAS_OBTRUSIVE | HAS_SLOW_PATH))) ||
936 *old_state & HAS_OBTRUSIVE)
937 {
938 mysql_prlock_assert_write_owner(&m_rwlock);
939 }
940 #endif
941 /*
942 We should not change state of destroyed object
943 (fast_path_state_reset() being exception).
944 */
945 assert(! (*old_state & IS_DESTROYED));
946
947 return my_atomic_cas64(&m_fast_path_state, old_state, new_state);
948 }
949
950 /**
951 Wrapper for my_atomic_add64 operation on m_fast_path_state member
952 which enforces locking and other invariants.
953 */
fast_path_state_add(fast_path_state_t value)954 fast_path_state_t fast_path_state_add(fast_path_state_t value)
955 {
956 /*
957 Invariant [INV1] requires all changes to m_fast_path_state happen
958 under protection of m_rwlock if HAS_OBTRUSIVE flag is set.
959 Since this operation doesn't check this flag it can be called only
960 under protection of m_rwlock.
961 */
962 mysql_prlock_assert_write_owner(&m_rwlock);
963
964 fast_path_state_t old_state= my_atomic_add64(&m_fast_path_state, value);
965
966 /*
967 We should not change state of destroyed object
968 (fast_path_state_reset() being exception).
969 */
970 assert(! (old_state & IS_DESTROYED));
971 return old_state;
972 }
973
974 /**
975 Wrapper for resetting m_fast_path_state enforcing locking invariants.
976 */
fast_path_state_reset()977 void fast_path_state_reset()
978 {
979 /* HAS_DESTROYED flag can be cleared only under protection of m_rwlock. */
980 mysql_prlock_assert_write_owner(&m_rwlock);
981 my_atomic_store64(&m_fast_path_state, 0);
982 }
983
984 /**
985 Pointer to strategy object which defines how different types of lock
986 requests should be handled for the namespace to which this lock belongs.
987 @sa MDL_lock::m_scoped_lock_strategy and MDL_lock:m_object_lock_strategy.
988 */
989 const MDL_lock_strategy *m_strategy;
990
991 /**
992 Get bitmap of "unobtrusive" locks granted using "fast path" algorithm
993 for scoped locks.
994
995 @sa MDL_lock::fast_path_granted_bitmap() for explanation about why it
996 is safe to use non-atomic read of MDL_lock::m_fast_path_state here.
997 */
scoped_lock_fast_path_granted_bitmap(const MDL_lock & lock)998 static bitmap_t scoped_lock_fast_path_granted_bitmap(const MDL_lock &lock)
999 {
1000 return (lock.m_fast_path_state & 0xFFFFFFFFFFFFFFFULL) ?
1001 MDL_BIT(MDL_INTENTION_EXCLUSIVE) : 0;
1002 }
1003
1004 /**
1005 Check if we are requesting X lock on the object, so threads holding
1006 conflicting S/SH metadata locks on it need to be notified.
1007
1008 @sa MDL_lock::object_lock_notify_conflicting_locks.
1009 */
object_lock_needs_notification(const MDL_ticket * ticket)1010 static bool object_lock_needs_notification(const MDL_ticket *ticket)
1011 {
1012 return (ticket->get_type() == MDL_EXCLUSIVE);
1013 }
1014 static void object_lock_notify_conflicting_locks(MDL_context *ctx,
1015 MDL_lock *lock);
1016 /**
1017 Get bitmap of "unobtrusive" locks granted using "fast path" algorithm
1018 for per-object locks.
1019
1020 @sa MDL_lock::fast_path_granted_bitmap() for explanation about why it
1021 is safe to use non-atomic read of MDL_lock::m_fast_path_state here.
1022 */
object_lock_fast_path_granted_bitmap(const MDL_lock & lock)1023 static bitmap_t object_lock_fast_path_granted_bitmap(const MDL_lock &lock)
1024 {
1025 bitmap_t result= 0;
1026 fast_path_state_t fps= lock.m_fast_path_state;
1027 if (fps & 0xFFFFFULL)
1028 result|= MDL_BIT(MDL_SHARED);
1029 if (fps & (0xFFFFFULL << 20))
1030 result|= MDL_BIT(MDL_SHARED_READ);
1031 if (fps & (0xFFFFFULL << 40))
1032 result|= MDL_BIT(MDL_SHARED_WRITE);
1033 return result;
1034 }
1035
1036 /**
1037 Check if MDL_lock object represents user-level lock or locking service
1038 lock, so threads waiting for it need to check if connection is lost
1039 and abort waiting when it is.
1040 */
object_lock_needs_connection_check(const MDL_lock * lock)1041 static bool object_lock_needs_connection_check(const MDL_lock *lock)
1042 {
1043 return (lock->key.mdl_namespace() == MDL_key::USER_LEVEL_LOCK ||
1044 lock->key.mdl_namespace() == MDL_key::LOCKING_SERVICE);
1045 }
1046
1047 /**
1048 Bitmap with "hog" lock types for object locks.
1049
1050 Locks of these types can easily starve out lower priority locks.
1051 To prevent this we only grant them max_write_lock_count times in
1052 a row while other lock types are waiting.
1053 */
1054 static const bitmap_t MDL_OBJECT_HOG_LOCK_TYPES=
1055 (MDL_BIT(MDL_SHARED_NO_WRITE) |
1056 MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
1057 MDL_BIT(MDL_EXCLUSIVE));
1058
1059
1060 static const MDL_lock_strategy m_scoped_lock_strategy;
1061 static const MDL_lock_strategy m_object_lock_strategy;
1062 };
1063
1064
1065 static MDL_map mdl_locks;
1066
1067
1068 extern "C"
1069 {
1070 static uchar *
mdl_locks_key(const uchar * record,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))1071 mdl_locks_key(const uchar *record, size_t *length,
1072 my_bool not_used MY_ATTRIBUTE((unused)))
1073 {
1074 MDL_lock *lock=(MDL_lock*) record;
1075 *length= lock->key.length();
1076 return (uchar*) lock->key.ptr();
1077 }
1078 } /* extern "C" */
1079
1080
1081 /**
1082 Initialize the metadata locking subsystem.
1083
1084 This function is called at server startup.
1085
1086 In particular, initializes the new global mutex and
1087 the associated condition variable: LOCK_mdl and COND_mdl.
1088 These locking primitives are implementation details of the MDL
1089 subsystem and are private to it.
1090 */
1091
mdl_init()1092 void mdl_init()
1093 {
1094 assert(! mdl_initialized);
1095 mdl_initialized= TRUE;
1096
1097 #ifdef HAVE_PSI_INTERFACE
1098 init_mdl_psi_keys();
1099 #endif
1100
1101 mdl_locks.init();
1102 }
1103
1104
1105 /**
1106 Release resources of metadata locking subsystem.
1107
1108 Destroys the global mutex and the condition variable.
1109 Called at server shutdown.
1110 */
1111
mdl_destroy()1112 void mdl_destroy()
1113 {
1114 if (mdl_initialized)
1115 {
1116 mdl_initialized= FALSE;
1117 mdl_locks.destroy();
1118 }
1119 }
1120
1121
1122 /**
1123 Get number of unused MDL_lock objects in MDL_map cache.
1124 Mostly needed for unit-testing.
1125 */
1126
mdl_get_unused_locks_count()1127 int32 mdl_get_unused_locks_count()
1128 {
1129 return mdl_locks.get_unused_locks_count();
1130 }
1131
1132
1133 extern "C"
1134 {
mdl_lock_cons(uchar * arg)1135 static void mdl_lock_cons(uchar *arg)
1136 {
1137 new (arg+LF_HASH_OVERHEAD) MDL_lock();
1138 }
1139
mdl_lock_dtor(uchar * arg)1140 static void mdl_lock_dtor(uchar *arg)
1141 {
1142 MDL_lock *lock= (MDL_lock *)(arg+LF_HASH_OVERHEAD);
1143 lock->~MDL_lock();
1144 }
1145
mdl_lock_reinit(uchar * dst_arg,const uchar * src_arg)1146 static void mdl_lock_reinit(uchar *dst_arg, const uchar *src_arg)
1147 {
1148 MDL_lock *dst= (MDL_lock *)dst_arg;
1149 const MDL_key *src= (const MDL_key *)src_arg;
1150 dst->reinit(src);
1151 }
1152
1153 /**
1154 Adapter function which allows to use murmur3 with LF_HASH implementation.
1155 */
1156
murmur3_adapter(const LF_HASH *,const uchar * key,size_t length)1157 static uint murmur3_adapter(const LF_HASH*, const uchar *key, size_t length)
1158 {
1159 return murmur3_32(key, length, 0);
1160 }
1161
1162 } /* extern "C" */
1163
1164
1165 /** Initialize the container for all MDL locks. */
1166
init()1167 void MDL_map::init()
1168 {
1169 MDL_key global_lock_key(MDL_key::GLOBAL, "", "");
1170 MDL_key commit_lock_key(MDL_key::COMMIT, "", "");
1171 MDL_key backup_lock_key(MDL_key::BACKUP, "", "");
1172 MDL_key binlog_lock_key(MDL_key::BINLOG, "", "");
1173
1174 m_global_lock= MDL_lock::create(&global_lock_key);
1175 m_commit_lock= MDL_lock::create(&commit_lock_key);
1176 m_backup_lock= MDL_lock::create(&backup_lock_key);
1177 m_binlog_lock= MDL_lock::create(&binlog_lock_key);
1178
1179 m_unused_lock_objects= 0;
1180
1181 lf_hash_init2(&m_locks, sizeof(MDL_lock), LF_HASH_UNIQUE,
1182 0, 0, mdl_locks_key, &my_charset_bin, &murmur3_adapter,
1183 &mdl_lock_cons, &mdl_lock_dtor, &mdl_lock_reinit);
1184 }
1185
1186
1187 /**
1188 Destroy the container for all MDL locks.
1189 @pre It must be empty.
1190 */
1191
destroy()1192 void MDL_map::destroy()
1193 {
1194 MDL_lock::destroy(m_backup_lock);
1195 MDL_lock::destroy(m_binlog_lock);
1196 MDL_lock::destroy(m_global_lock);
1197 MDL_lock::destroy(m_commit_lock);
1198
1199 lf_hash_destroy(&m_locks);
1200 }
1201
1202
1203 /**
1204 Find MDL_lock object corresponding to the key.
1205
1206 @param[in/out] pins LF_PINS to be used for pinning pointers during
1207 look-up and returned MDL_lock object.
1208 @param[in] mdl_key Key for which MDL_lock object needs to be found.
1209 @param[out] pinned TRUE - if MDL_lock object is pinned,
1210 FALSE - if MDL_lock object doesn't require pinning
1211 (i.e. it is an object for GLOBAL or COMMIT
1212 namespaces).
1213
1214 @retval MY_ERRPTR - Failure (OOM)
1215 @retval other-non-NULL - MDL_lock object found.
1216 @retval NULL - Object not found.
1217 */
1218
find(LF_PINS * pins,const MDL_key * mdl_key,bool * pinned)1219 MDL_lock* MDL_map::find(LF_PINS *pins, const MDL_key *mdl_key, bool *pinned)
1220 {
1221 MDL_lock *lock;
1222
1223 if (is_lock_object_singleton(mdl_key))
1224 {
1225 /*
1226 Avoid look up in m_locks hash when lock for GLOBAL or COMMIT namespace
1227 is requested. Return pointer to pre-allocated MDL_lock instance instead.
1228 Such an optimization allows us to avoid a few atomic operations for any
1229 statement changing data.
1230
1231 It works since these namespaces contain only one element so keys
1232 for them look like '<namespace-id>\0\0'.
1233 */
1234 assert(mdl_key->length() == 3);
1235
1236 switch (mdl_key->mdl_namespace())
1237 {
1238 case MDL_key::GLOBAL:
1239 lock= m_global_lock;
1240 break;
1241 case MDL_key::COMMIT:
1242 lock= m_commit_lock;
1243 break;
1244 case MDL_key::BACKUP:
1245 lock= m_backup_lock;
1246 break;
1247 case MDL_key::BINLOG:
1248 lock= m_binlog_lock;
1249 break;
1250 default:
1251 MY_ASSERT_UNREACHABLE();
1252 }
1253
1254 *pinned= false;
1255
1256 return lock;
1257 }
1258
1259 lock= static_cast<MDL_lock *>(lf_hash_search(&m_locks, pins, mdl_key->ptr(),
1260 mdl_key->length()));
1261
1262 if (lock == NULL || lock == MY_ERRPTR)
1263 {
1264 lf_hash_search_unpin(pins);
1265 *pinned= false; // Avoid warnings on older compilers.
1266 return lock;
1267 }
1268
1269 *pinned= true;
1270
1271 return lock;
1272 }
1273
1274
1275 /**
1276 Find MDL_lock object corresponding to the key, create it
1277 if it does not exist.
1278
1279 @param[in/out] pins LF_PINS to be used for pinning pointers during
1280 look-up and returned MDL_lock object.
1281 @param[in] mdl_key Key for which MDL_lock object needs to be found.
1282 @param[out] pinned TRUE - if MDL_lock object is pinned,
1283 FALSE - if MDL_lock object doesn't require pinning
1284 (i.e. it is an object for GLOBAL or COMMIT
1285 namespaces).
1286
1287 @retval non-NULL - Success. MDL_lock instance for the key with
1288 locked MDL_lock::m_rwlock.
1289 @retval NULL - Failure (OOM).
1290 */
1291
find_or_insert(LF_PINS * pins,const MDL_key * mdl_key,bool * pinned)1292 MDL_lock* MDL_map::find_or_insert(LF_PINS *pins, const MDL_key *mdl_key,
1293 bool *pinned)
1294 {
1295 MDL_lock *lock;
1296
1297 while ((lock= find(pins, mdl_key, pinned)) == NULL)
1298 {
1299 /*
1300 MDL_lock for key isn't present in hash, try to insert new object.
1301 This can fail due to concurrent inserts.
1302 */
1303 int rc= lf_hash_insert(&m_locks, pins, mdl_key);
1304 if (rc == -1) /* If OOM. */
1305 return NULL;
1306 else if (rc == 0)
1307 {
1308 /*
1309 New MDL_lock object is not used yet. So we need to
1310 increment number of unused lock objects.
1311 */
1312 my_atomic_add32(&m_unused_lock_objects, 1);
1313 }
1314 }
1315 if (lock == MY_ERRPTR)
1316 {
1317 /* If OOM in lf_hash_search. */
1318 return NULL;
1319 }
1320
1321 return lock;
1322 }
1323
1324
1325 extern "C"
1326 {
1327 /**
1328 Helper function which allows to check if MDL_lock object stored in LF_HASH
1329 is unused - i.e. doesn't have any locks on both "fast" and "slow" paths
1330 and is not marked as deleted.
1331 */
mdl_lock_match_unused(const uchar * arg)1332 static int mdl_lock_match_unused(const uchar *arg)
1333 {
1334 const MDL_lock *lock= (const MDL_lock *)arg;
1335 /*
1336 It is OK to check MDL_lock::m_fast_path_state non-atomically here
1337 since the fact that MDL_lock object is unused will be properly
1338 validated later anyway.
1339 */
1340 return (lock->m_fast_path_state == 0);
1341 }
1342 } /* extern "C" */
1343
1344
1345 /**
1346 Try to find random MDL_lock object in MDL_map for which there are no "fast"
1347 path nor "slow" path locks. If found - mark it as destroyed, remove object
1348 from MDL_map and return it back to allocator.
1349
1350 @param[in] ctx Context on which behalf we are trying to remove
1351 unused object. Primarily needed to generate
1352 random value to be used for random dive into
1353 the hash in MDL_map.
1354 @param[in/out] pins Pins for the calling thread to be used for
1355 hash lookup and deletion.
1356 @param[out] unused_locks Number of unused lock objects after operation.
1357
1358 @note
1359 In reality MDL_lock object will be returned to allocator once it is no
1360 longer pinned by any threads.
1361 */
1362
remove_random_unused(MDL_context * ctx,LF_PINS * pins,int32 * unused_locks)1363 void MDL_map::remove_random_unused(MDL_context *ctx, LF_PINS *pins,
1364 int32 *unused_locks)
1365 {
1366 DEBUG_SYNC(ctx->get_thd(), "mdl_remove_random_unused_before_search");
1367
1368 /*
1369 Try to find an unused MDL_lock object by doing random dive into the hash.
1370 Since this method is called only when unused/total lock objects ratio is
1371 high enough, there is a good chance for this technique to succeed.
1372 */
1373 MDL_lock *lock= static_cast<MDL_lock *>(lf_hash_random_match(&m_locks,
1374 pins, &mdl_lock_match_unused,
1375 ctx->get_random()));
1376
1377 if (lock == NULL || lock == MY_ERRPTR)
1378 {
1379 /*
1380 We were unlucky and no unused objects were found. This can happen,
1381 for example, if our random dive into LF_HASH was close to the tail
1382 of split-ordered list used in its implementation or if some other
1383 thread managed to destroy or start re-using MDL_lock object
1384 concurrently.
1385 */
1386 lf_hash_search_unpin(pins);
1387 *unused_locks= m_unused_lock_objects;
1388 return;
1389 }
1390
1391 DEBUG_SYNC(ctx->get_thd(), "mdl_remove_random_unused_after_search");
1392
1393 /*
1394 Acquire MDL_lock::m_rwlock to ensure that IS_DESTROYED flag is set
1395 atomically AND under protection of MDL_lock::m_rwlock, so it can be
1396 safely read using both atomics and ordinary read under protection of
1397 m_rwlock. This also means that it is safe to unpin MDL_lock object
1398 after we have checked its IS_DESTROYED flag if we keep m_rwlock lock.
1399 */
1400 mysql_prlock_wrlock(&lock->m_rwlock);
1401
1402 if (lock->m_fast_path_state & MDL_lock::IS_DESTROYED)
1403 {
1404 /*
1405 Somebody has managed to mark MDL_lock object as destroyed before
1406 we have acquired MDL_lock::m_rwlock.
1407 */
1408 mysql_prlock_unlock(&lock->m_rwlock);
1409 lf_hash_search_unpin(pins);
1410 *unused_locks= m_unused_lock_objects;
1411 return;
1412 }
1413 lf_hash_search_unpin(pins);
1414
1415 /*
1416 Atomically check that number of "fast path" and "slow path" locks is 0 and
1417 set IS_DESTROYED flag.
1418
1419 This is the only place where we rely on the fact that our compare-and-swap
1420 operation can't spuriously fail i.e. is of strong kind.
1421 */
1422 MDL_lock::fast_path_state_t old_state= 0;
1423
1424 if (lock->fast_path_state_cas(&old_state, MDL_lock::IS_DESTROYED))
1425 {
1426 /*
1427 There were no "fast path" or "slow path" references and we
1428 have successfully set IS_DESTROYED flag.
1429 */
1430 mysql_prlock_unlock(&lock->m_rwlock);
1431
1432 DEBUG_SYNC(ctx->get_thd(), "mdl_remove_random_unused_after_is_destroyed_set");
1433
1434 /*
1435 Even though other threads can't rely on the MDL_lock object being around
1436 once IS_DESTROYED flag is set, we know that it was not removed from
1437 the hash yet (as it is responsibility of the current thread, i.e. one
1438 which executes this MDL_map::remove_random_unused() call) and thus was
1439 not deallocated.
1440 And since lf_hash_delete() finds and pins the object for the key as its
1441 first step and keeps pins until its end it is safe to use MDL_lock::key
1442 as parameter to lf_hash_delete().
1443 */
1444 int rc= lf_hash_delete(&m_locks, pins, lock->key.ptr(), lock->key.length());
1445
1446 /* The MDL_lock object must be present in the hash. */
1447 assert(rc != 1);
1448
1449 if (rc == -1)
1450 {
1451 /*
1452 In unlikely case of OOM MDL_lock object stays in the hash. The best
1453 thing we can do is to reset IS_DESTROYED flag. The object will be
1454 destroyed either by further calls to lf_hash_delete() or by final
1455 call to lf_hash_destroy().
1456 Resetting needs to happen atomically AND under protection of
1457 MDL_lock::m_rwlock so it safe to read this flag both using atomics
1458 and ordinary reads under protection of m_rwlock lock.
1459 */
1460 mysql_prlock_wrlock(&lock->m_rwlock);
1461 lock->fast_path_state_reset();
1462 mysql_prlock_unlock(&lock->m_rwlock);
1463 }
1464 else
1465 {
1466 /* Success. */
1467 *unused_locks= my_atomic_add32(&m_unused_lock_objects, -1) - 1;
1468 }
1469 }
1470 else
1471 {
1472 /*
1473 Some other thread has managed to find and use this MDL_lock object after
1474 it has been found by the above call to lf_hash_random_match().
1475 There are/were "fast" or "slow path" references so MDL_lock object can't
1476 be deleted.
1477
1478 Assert that compare-and-swap operation is of strong kind and can't
1479 fail spuriously.
1480 */
1481 assert(old_state != 0);
1482 mysql_prlock_unlock(&lock->m_rwlock);
1483 *unused_locks= m_unused_lock_objects;
1484 }
1485 }
1486
1487
1488 /**
1489 Initialize a metadata locking context.
1490
1491 This is to be called when a new server connection is created.
1492 */
1493
MDL_context()1494 MDL_context::MDL_context()
1495 :
1496 m_owner(NULL),
1497 m_needs_thr_lock_abort(FALSE),
1498 m_force_dml_deadlock_weight(false),
1499 m_waiting_for(NULL),
1500 m_pins(NULL),
1501 m_rand_state(UINT_MAX32)
1502 {
1503 mysql_prlock_init(key_MDL_context_LOCK_waiting_for, &m_LOCK_waiting_for);
1504 }
1505
1506
1507 /**
1508 Destroy metadata locking context.
1509
1510 Assumes and asserts that there are no active or pending locks
1511 associated with this context at the time of the destruction.
1512
1513 Currently does nothing. Asserts that there are no pending
1514 or satisfied lock requests. The pending locks must be released
1515 prior to destruction. This is a new way to express the assertion
1516 that all tables are closed before a connection is destroyed.
1517 */
1518
destroy()1519 void MDL_context::destroy()
1520 {
1521 assert(m_tickets[MDL_STATEMENT].is_empty());
1522 assert(m_tickets[MDL_TRANSACTION].is_empty());
1523 assert(m_tickets[MDL_EXPLICIT].is_empty());
1524
1525 mysql_prlock_destroy(&m_LOCK_waiting_for);
1526 if (m_pins)
1527 lf_hash_put_pins(m_pins);
1528 }
1529
1530
1531 /**
1532 Allocate pins which are necessary to work with MDL_map container
1533 if they are not allocated already.
1534 */
1535
fix_pins()1536 bool MDL_context::fix_pins()
1537 {
1538 if (! m_pins)
1539 m_pins= mdl_locks.get_pins();
1540 return (m_pins == NULL);
1541 }
1542
1543
1544 /**
1545 Initialize a lock request.
1546
1547 This is to be used for every lock request.
1548
1549 Note that initialization and allocation are split into two
1550 calls. This is to allow flexible memory management of lock
1551 requests. Normally a lock request is stored in statement memory
1552 (e.g. is a member of struct TABLE_LIST), but we would also like
1553 to allow allocation of lock requests in other memory roots,
1554 for example in the grant subsystem, to lock privilege tables.
1555
1556 The MDL subsystem does not own or manage memory of lock requests.
1557
1558 @param mdl_namespace Id of namespace of object to be locked
1559 @param db Name of database to which the object belongs
1560 @param name Name of of the object
1561 @param mdl_type The MDL lock type for the request.
1562 */
1563
init_with_source(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,const char * src_file,uint src_line)1564 void MDL_request::init_with_source(MDL_key::enum_mdl_namespace mdl_namespace,
1565 const char *db_arg,
1566 const char *name_arg,
1567 enum_mdl_type mdl_type_arg,
1568 enum_mdl_duration mdl_duration_arg,
1569 const char *src_file,
1570 uint src_line)
1571 {
1572 key.mdl_key_init(mdl_namespace, db_arg, name_arg);
1573 type= mdl_type_arg;
1574 duration= mdl_duration_arg;
1575 ticket= NULL;
1576 m_src_file= src_file;
1577 m_src_line= src_line;
1578 }
1579
1580
1581 /**
1582 Initialize a lock request using pre-built MDL_key.
1583
1584 @sa MDL_request::init(namespace, db, name, type).
1585
1586 @param key_arg The pre-built MDL key for the request.
1587 @param mdl_type_arg The MDL lock type for the request.
1588 */
1589
init_by_key_with_source(const MDL_key * key_arg,enum_mdl_type mdl_type_arg,enum_mdl_duration mdl_duration_arg,const char * src_file,uint src_line)1590 void MDL_request::init_by_key_with_source(const MDL_key *key_arg,
1591 enum_mdl_type mdl_type_arg,
1592 enum_mdl_duration mdl_duration_arg,
1593 const char *src_file,
1594 uint src_line)
1595 {
1596 key.mdl_key_init(key_arg);
1597 type= mdl_type_arg;
1598 duration= mdl_duration_arg;
1599 ticket= NULL;
1600 m_src_file= src_file;
1601 m_src_line= src_line;
1602 }
1603
1604
1605 /**
1606 Auxiliary functions needed for creation/destruction of MDL_lock objects.
1607 */
1608
create(const MDL_key * mdl_key)1609 inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key)
1610 {
1611 MDL_lock *result= new (std::nothrow) MDL_lock();
1612 if (result)
1613 result->reinit(mdl_key);
1614 return result;
1615 }
1616
1617
destroy(MDL_lock * lock)1618 void MDL_lock::destroy(MDL_lock *lock)
1619 {
1620 delete lock;
1621 }
1622
1623
1624 /**
1625 Finalize initialization or re-initialize MDL_lock returned from
1626 LF_ALLOCATOR's cache to represent object identified by provided key.
1627
1628 @note All non-static MDL_lock members:
1629 1) either have to be reinitialized here
1630 (like IS_DESTROYED flag in MDL_lock::m_fast_path_state).
1631 2) or need to be initialized in constructor AND returned to their
1632 pristine state once they are removed from MDL_map container
1633 (like MDL_lock::m_granted or MDL_lock::m_rwlock).
1634 Otherwise it is possible that we will end up in situation
1635 when "new" (actually reused) MDL_lock object inserted in
1636 LF_HASH will inherit some values from old object.
1637 */
1638
reinit(const MDL_key * mdl_key)1639 inline void MDL_lock::reinit(const MDL_key *mdl_key)
1640 {
1641 key.mdl_key_init(mdl_key);
1642 switch (mdl_key->mdl_namespace())
1643 {
1644 case MDL_key::GLOBAL:
1645 case MDL_key::TABLESPACE:
1646 case MDL_key::SCHEMA:
1647 case MDL_key::COMMIT:
1648 case MDL_key::BACKUP:
1649 case MDL_key::BINLOG:
1650 m_strategy= &m_scoped_lock_strategy;
1651 break;
1652 default:
1653 m_strategy= &m_object_lock_strategy;
1654 break;
1655 }
1656 m_hog_lock_count= 0;
1657 m_piglet_lock_count= 0;
1658 m_current_waiting_incompatible_idx= 0;
1659 m_fast_path_state= 0;
1660 /*
1661 Check that we have clean "m_granted" and "m_waiting" sets/lists in both
1662 cases when we have fresh and re-used object.
1663 */
1664 assert(m_granted.is_empty() && m_waiting.is_empty());
1665 /* The same should be true for "m_obtrusive_locks_granted_waiting_count". */
1666 assert(m_obtrusive_locks_granted_waiting_count == 0);
1667 }
1668
1669
1670 /**
1671 @returns "Fast path" increment for request for "unobtrusive" type
1672 of lock, 0 - if it is request for "obtrusive" type of
1673 lock.
1674
1675 @sa Description at method declaration for more details.
1676 */
1677
1678 MDL_lock::fast_path_state_t
get_unobtrusive_lock_increment(const MDL_request * request)1679 MDL_lock::get_unobtrusive_lock_increment(const MDL_request *request)
1680 {
1681 switch (request->key.mdl_namespace())
1682 {
1683 case MDL_key::GLOBAL:
1684 case MDL_key::TABLESPACE:
1685 case MDL_key::SCHEMA:
1686 case MDL_key::COMMIT:
1687 case MDL_key::BACKUP:
1688 case MDL_key::BINLOG:
1689 return m_scoped_lock_strategy.m_unobtrusive_lock_increment[request->type];
1690 default:
1691 return m_object_lock_strategy.m_unobtrusive_lock_increment[request->type];
1692 }
1693 }
1694
1695
1696 /**
1697 Indicates whether object belongs to namespace which requires storage engine
1698 to be notified before acquiring and after releasing exclusive lock.
1699 */
1700
1701 bool
needs_hton_notification(MDL_key::enum_mdl_namespace mdl_namespace)1702 MDL_lock::needs_hton_notification(MDL_key::enum_mdl_namespace mdl_namespace)
1703 {
1704 switch (mdl_namespace)
1705 {
1706 case MDL_key::TABLESPACE:
1707 case MDL_key::SCHEMA:
1708 case MDL_key::TABLE:
1709 case MDL_key::FUNCTION:
1710 case MDL_key::PROCEDURE:
1711 case MDL_key::TRIGGER:
1712 case MDL_key::EVENT:
1713 return true;
1714 default:
1715 return false;
1716 }
1717 }
1718
1719 /**
1720 Auxiliary functions needed for creation/destruction of MDL_ticket
1721 objects.
1722
1723 @todo This naive implementation should be replaced with one that saves
1724 on memory allocation by reusing released objects.
1725 */
1726
create(MDL_context * ctx_arg,enum_mdl_type type_arg,enum_mdl_duration duration_arg)1727 MDL_ticket *MDL_ticket::create(MDL_context *ctx_arg, enum_mdl_type type_arg
1728 #ifndef NDEBUG
1729 , enum_mdl_duration duration_arg
1730 #endif
1731 )
1732 {
1733 return new (std::nothrow)
1734 MDL_ticket(ctx_arg, type_arg
1735 #ifndef NDEBUG
1736 , duration_arg
1737 #endif
1738 );
1739 }
1740
1741
destroy(MDL_ticket * ticket)1742 void MDL_ticket::destroy(MDL_ticket *ticket)
1743 {
1744 mysql_mdl_destroy(ticket->m_psi);
1745 ticket->m_psi= NULL;
1746
1747 delete ticket;
1748 }
1749
1750
1751 /**
1752 Return the 'weight' of this ticket for the victim selection algorithm.
1753 Requests with lower weight are preferred to requests with higher weight
1754 when choosing a victim.
1755
1756 @note When MDL_context::m_force_dml_deadlock_weight is set, the return value
1757 of this method is ignored and DEADLOCK_WEIGHT_DML is used for the
1758 context.
1759 */
1760
get_deadlock_weight() const1761 uint MDL_ticket::get_deadlock_weight() const
1762 {
1763 /*
1764 Waits for user-level locks have lower weight than waits for locks
1765 typically acquired by DDL, so we don't abort DDL in case of deadlock
1766 involving user-level locks and DDL. Deadlock errors are not normally
1767 expected from DDL by users.
1768 Waits for user-level locks have higher weight than waits for locks
1769 acquired by DML, so we prefer to abort DML in case of deadlock involving
1770 user-level locks and DML. User-level locks are explicitly requested by
1771 user, so they are probably important for them. Plus users expect
1772 deadlocks from DML transactions and for DML statements executed in
1773 @@autocommit=1 mode back-off and retry algorithm hides deadlock errors.
1774 */
1775 if (m_lock->key.mdl_namespace() == MDL_key::USER_LEVEL_LOCK)
1776 return DEADLOCK_WEIGHT_ULL;
1777
1778 /*
1779 Locks higher or equal to MDL_SHARED_UPGRADABLE:
1780 *) Are typically acquired for DDL and LOCK TABLES statements.
1781 *) Are often acquired in a way which doesn't allow simple release of
1782 locks and restart of lock acquisition process in case of deadlock
1783 (e.g. through lock_table_names() call).
1784
1785 To avoid such statements getting aborted with ER_LOCK_DEADLOCK error
1786 we use the higher DEADLOCK_WEIGHT_DDL weight for them.
1787
1788 Note that two DDL statements should not typically deadlock with each
1789 other since they normally acquire locks in the same order, thanks to
1790 to the fact that lock_table_names() uses MDL_context::acquire_locks()
1791 method which sorts lock requests before trying to acquire them.
1792
1793 In cases when "strong" locks can be acquired out-of-order (e.g. for
1794 LOCK TABLES) we try to use DEADLOCK_WEIGHT_DML instead.
1795
1796 TODO/FIXME: The below condition needs to be updated. The fact that a
1797 lock from GLOBAL namespace is requested no longer means
1798 that this is a DDL statement. There is a bug report about
1799 this.
1800 */
1801 if (m_lock->key.mdl_namespace() == MDL_key::GLOBAL ||
1802 m_type >= MDL_SHARED_UPGRADABLE)
1803 return DEADLOCK_WEIGHT_DDL;
1804
1805 return DEADLOCK_WEIGHT_DML;
1806 }
1807
1808
1809 /** Construct an empty wait slot. */
1810
MDL_wait()1811 MDL_wait::MDL_wait()
1812 :m_wait_status(EMPTY)
1813 {
1814 mysql_mutex_init(key_MDL_wait_LOCK_wait_status, &m_LOCK_wait_status, NULL);
1815 mysql_cond_init(key_MDL_wait_COND_wait_status, &m_COND_wait_status);
1816 }
1817
1818
1819 /** Destroy system resources. */
1820
~MDL_wait()1821 MDL_wait::~MDL_wait()
1822 {
1823 mysql_mutex_destroy(&m_LOCK_wait_status);
1824 mysql_cond_destroy(&m_COND_wait_status);
1825 }
1826
1827
1828 /**
1829 Set the status unless it's already set. Return FALSE if set,
1830 TRUE otherwise.
1831 */
1832
set_status(enum_wait_status status_arg)1833 bool MDL_wait::set_status(enum_wait_status status_arg)
1834 {
1835 bool was_occupied= TRUE;
1836 mysql_mutex_lock(&m_LOCK_wait_status);
1837 if (m_wait_status == EMPTY)
1838 {
1839 was_occupied= FALSE;
1840 m_wait_status= status_arg;
1841 mysql_cond_signal(&m_COND_wait_status);
1842 }
1843 mysql_mutex_unlock(&m_LOCK_wait_status);
1844 return was_occupied;
1845 }
1846
1847
1848 /** Query the current value of the wait slot. */
1849
get_status()1850 MDL_wait::enum_wait_status MDL_wait::get_status()
1851 {
1852 enum_wait_status result;
1853 mysql_mutex_lock(&m_LOCK_wait_status);
1854 result= m_wait_status;
1855 mysql_mutex_unlock(&m_LOCK_wait_status);
1856 return result;
1857 }
1858
1859
1860 /** Clear the current value of the wait slot. */
1861
reset_status()1862 void MDL_wait::reset_status()
1863 {
1864 mysql_mutex_lock(&m_LOCK_wait_status);
1865 m_wait_status= EMPTY;
1866 mysql_mutex_unlock(&m_LOCK_wait_status);
1867 }
1868
1869
1870 /**
1871 Wait for the status to be assigned to this wait slot.
1872
1873 @param owner MDL context owner.
1874 @param abs_timeout Absolute time after which waiting should stop.
1875 @param set_status_on_timeout TRUE - If in case of timeout waiting
1876 context should close the wait slot by
1877 sending TIMEOUT to itself.
1878 FALSE - Otherwise.
1879 @param wait_state_name Thread state name to be set for duration of wait.
1880
1881 @returns Signal posted.
1882 */
1883
1884 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)1885 MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
1886 bool set_status_on_timeout,
1887 const PSI_stage_info *wait_state_name)
1888 {
1889 PSI_stage_info old_stage;
1890 enum_wait_status result;
1891 int wait_result= 0;
1892
1893 mysql_mutex_lock(&m_LOCK_wait_status);
1894
1895 owner->ENTER_COND(&m_COND_wait_status, &m_LOCK_wait_status,
1896 wait_state_name, & old_stage);
1897 thd_wait_begin(NULL, THD_WAIT_META_DATA_LOCK);
1898 while (!m_wait_status && !owner->is_killed() &&
1899 wait_result != ETIMEDOUT && wait_result != ETIME)
1900 {
1901 wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
1902 abs_timeout);
1903 }
1904 thd_wait_end(NULL);
1905
1906 if (m_wait_status == EMPTY)
1907 {
1908 /*
1909 Wait has ended not due to a status being set from another
1910 thread but due to this connection/statement being killed or a
1911 time out.
1912 To avoid races, which may occur if another thread sets
1913 GRANTED status before the code which calls this method
1914 processes the abort/timeout, we assign the status under
1915 protection of the m_LOCK_wait_status, within the critical
1916 section. An exception is when set_status_on_timeout is
1917 false, which means that the caller intends to restart the
1918 wait.
1919 */
1920 if (owner->is_killed())
1921 m_wait_status= KILLED;
1922 else if (set_status_on_timeout)
1923 m_wait_status= TIMEOUT;
1924 }
1925 result= m_wait_status;
1926
1927 mysql_mutex_unlock(&m_LOCK_wait_status);
1928 owner->EXIT_COND(& old_stage);
1929
1930 return result;
1931 }
1932
1933 /**
1934 Clear bit corresponding to the type of metadata lock in bitmap representing
1935 set of such types if list of tickets does not contain ticket with such type.
1936
1937 @param[in,out] bitmap Bitmap representing set of types of locks.
1938 @param[in] list List to inspect.
1939 @param[in] type Type of metadata lock to look up in the list.
1940 */
1941
clear_bit_if_not_in_list(enum_mdl_type type)1942 void MDL_lock::Ticket_list::clear_bit_if_not_in_list(enum_mdl_type type)
1943 {
1944 MDL_lock::Ticket_iterator it(m_list);
1945 const MDL_ticket *ticket;
1946
1947 while ((ticket= it++))
1948 if (ticket->get_type() == type)
1949 return;
1950 m_bitmap&= ~ MDL_BIT(type);
1951 }
1952
1953
1954 /**
1955 Add ticket to MDL_lock's list of waiting requests and
1956 update corresponding bitmap of lock types.
1957 */
1958
add_ticket(MDL_ticket * ticket)1959 void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket)
1960 {
1961 /*
1962 Ticket being added to the list must have MDL_ticket::m_lock set,
1963 since for such tickets methods accessing this member might be
1964 called by other threads.
1965 */
1966 assert(ticket->get_lock());
1967 /*
1968 Add ticket to the *back* of the queue to ensure fairness
1969 among requests with the same priority.
1970 */
1971 m_list.push_back(ticket);
1972 m_bitmap|= MDL_BIT(ticket->get_type());
1973 }
1974
1975
1976 /**
1977 Remove ticket from MDL_lock's list of requests and
1978 update corresponding bitmap of lock types.
1979 */
1980
remove_ticket(MDL_ticket * ticket)1981 void MDL_lock::Ticket_list::remove_ticket(MDL_ticket *ticket)
1982 {
1983 m_list.remove(ticket);
1984 /*
1985 Check if waiting queue has another ticket with the same type as
1986 one which was removed. If there is no such ticket, i.e. we have
1987 removed last ticket of particular type, then we need to update
1988 bitmap of waiting ticket's types.
1989 Note that in most common case, i.e. when shared lock is removed
1990 from waiting queue, we are likely to find ticket of the same
1991 type early without performing full iteration through the list.
1992 So this method should not be too expensive.
1993 */
1994 clear_bit_if_not_in_list(ticket->get_type());
1995 }
1996
1997
1998 /**
1999 Determine waiting contexts which requests for the lock can be
2000 satisfied, grant lock to them and wake them up.
2001
2002 @note Together with MDL_lock::add_ticket() this method implements
2003 fair scheduling among requests with the same priority.
2004 It tries to grant lock from the head of waiters list, while
2005 add_ticket() adds new requests to the back of this list.
2006
2007 */
2008
reschedule_waiters()2009 void MDL_lock::reschedule_waiters()
2010 {
2011 MDL_lock::Ticket_iterator it(m_waiting);
2012 MDL_ticket *ticket;
2013
2014 /*
2015 Find the first (and hence the oldest) waiting request which
2016 can be satisfied (taking into account priority). Grant lock to it.
2017 Repeat the process for the remainder of waiters.
2018 Note we don't need to re-start iteration from the head of the
2019 list after satisfying the first suitable request as in our case
2020 all compatible types of requests have the same priority.
2021
2022 TODO/FIXME: We should:
2023 - Either switch to scheduling without priorities
2024 which will allow to stop iteration through the
2025 list of waiters once we found the first ticket
2026 which can't be satisfied
2027 - Or implement some check using bitmaps which will
2028 allow to stop iteration in cases when, e.g., we
2029 grant SNRW lock and there are no pending S or
2030 SH locks.
2031 */
2032 while ((ticket= it++))
2033 {
2034 if (can_grant_lock(ticket->get_type(), ticket->get_ctx()))
2035 {
2036 if (! ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED))
2037 {
2038 /*
2039 Satisfy the found request by updating lock structures.
2040 It is OK to do so even after waking up the waiter since any
2041 session which tries to get any information about the state of
2042 this lock has to acquire MDL_lock::m_rwlock first and thus,
2043 when manages to do so, already sees an updated state of the
2044 MDL_lock object.
2045
2046 It doesn't matter if we are dealing with "obtrusive" lock here,
2047 we are moving lock request from waiting to granted lists,
2048 so m_obtrusive_locks_granted_waiting_count should stay the same.
2049 */
2050 m_waiting.remove_ticket(ticket);
2051 m_granted.add_ticket(ticket);
2052
2053 if (is_affected_by_max_write_lock_count())
2054 {
2055 /*
2056 Increase the counter of successively granted high priority "hog" or
2057 "piglet" locks, if we have granted one and there are pending
2058 lower priority locks.
2059 */
2060 if (count_piglets_and_hogs(ticket->get_type()))
2061 {
2062 /*
2063 Switch of priority matrice might have unblocked some lower-prio
2064 locks which are still compatible with the lock type we just have
2065 granted (for example, when we grant SNW lock and there are pending
2066 requests of SR type). Restart iteration to wake them up, otherwise
2067 we might get deadlocks.
2068 */
2069 it.rewind();
2070 continue;
2071 }
2072 }
2073 }
2074 /*
2075 If we could not update the wait slot of the waiter,
2076 it can be due to fact that its connection/statement was
2077 killed or it has timed out (i.e. the slot is not empty).
2078 Since in all such cases the waiter assumes that the lock was
2079 not been granted, we should keep the request in the waiting
2080 queue and look for another request to reschedule.
2081 */
2082 }
2083 }
2084
2085 if (is_affected_by_max_write_lock_count())
2086 {
2087 /*
2088 Reset number of successively granted higher-prio "hog"/"piglet" locks
2089 if there are no pending lower-prio conflicting locks.
2090 This ensures:
2091 - That m_hog_lock_count/m_piglet_lock_count is correctly reset after
2092 a strong lock is released and weak locks are granted (or there are
2093 no other lock requests).
2094 - That the situation when SNW lock is granted along with some SR/SRO
2095 locks, but SW locks are still blocked is handled correctly.
2096 - That m_hog_lock_count/m_piglet_lock_count is zero in all cases
2097 when there are no pending weak locks (e.g. when weak locks are
2098 removed due to deadlock, being killed or timeout).
2099
2100 Also switch priority matrice accordingly. Note that switch in
2101 this particular place doesn't require reschedule since:
2102
2103 1) We never switch to a matrice which prefers lower priority locks
2104 more than "hog"/"piglet" locks here (this might have happened if
2105 MDL_lock::switch_incompatible_waiting_types_bitmap_if_needed()
2106 was used instead and max_write_lock_count was decreased
2107 concurrently).
2108 2) When we switch from matrice #1 (which prefers SRO over SW) to
2109 default matrice #0 only the priority of SW vs SRO requests changes.
2110 Since the switch happens only when there are no pending SRO
2111 locks, no reschedule is required.
2112 3) When we switch from matrice #2 (which prefers all non-"nog" over
2113 "hog" requests) to default matrice #0 only the priority of "hog" vs
2114 non-"hog" requests changes. But since this happens when there are
2115 no non-"hog" requests, no reschedule is required.
2116 4) When we switch from matrice #3 (which prefers SRO over SW and
2117 non-"hog"-minus-SW over "hog" locks) to default matrice #0 only
2118 the priority of non-"hog"-minus-SW vs "hog" and SRO vs SW changes
2119 (see invariant [INV3]). Since the switch happens only when there
2120 are no pending non-"hog"-minus-SW/SRO requests, no reschedule is
2121 required.
2122
2123 Note that we might be switching priority matrice in a situation when we
2124 had pending SRO/non-"hog"/non-"hog"-minus-SW requests at the start of
2125 the call but they were granted during the loop. If some "piglet"/"hog"
2126 requests are compatible with those lower priority locks, they were
2127 granted as well. Those which were not compatible were not granted and
2128 should stay waiting until lower priority locks are released (in other
2129 words, the fact that a lock moved from pending to granted doesn't unblock
2130 additional requests, see invariant [INV2]).
2131 */
2132 if (m_current_waiting_incompatible_idx == 3)
2133 {
2134 /*
2135 We can't simply switch from matrice #3 to matrice #2 when there are no
2136 pending SRO locks, as that would allow a stream of concurrent SW and SRO
2137 requests to starve out "hog" locks when max_write_lock_count is set
2138 (there will be always pending SW or/and SRO locks in this case, so no
2139 switch back to matrice #0 will ever happen).
2140
2141 So we switch from matrice #3 to #0 directly and ignore pending SW/SWLP
2142 locks. This is OK as situation when matrice #3 is active can only
2143 occur when there were max_write_lock_count SW locks granted recently
2144 (before switch from #0 -> #1 which preceded switch #3 or before switch
2145 #2 -> #3).
2146 */
2147 if ((m_waiting.bitmap() & ~(MDL_OBJECT_HOG_LOCK_TYPES |
2148 MDL_BIT(MDL_SHARED_WRITE) |
2149 MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO))) == 0)
2150 {
2151 m_piglet_lock_count= 0;
2152 m_hog_lock_count= 0;
2153 m_current_waiting_incompatible_idx= 0;
2154 }
2155 }
2156 else
2157 {
2158 if ((m_waiting.bitmap() & ~MDL_OBJECT_HOG_LOCK_TYPES) == 0)
2159 {
2160 m_hog_lock_count= 0;
2161 m_current_waiting_incompatible_idx&= ~2;
2162 }
2163 if ((m_waiting.bitmap() & MDL_BIT(MDL_SHARED_READ_ONLY)) == 0)
2164 {
2165 m_piglet_lock_count= 0;
2166 m_current_waiting_incompatible_idx&= ~1;
2167 }
2168 }
2169 }
2170 }
2171
2172
2173 /**
2174 Strategy instances to be used with scoped metadata locks (i.e. locks
2175 from GLOBAL, COMMIT, TABLESPACE and SCHEMA namespaces).
2176 The only locking modes which are supported at the moment are SHARED and
2177 INTENTION EXCLUSIVE and EXCLUSIVE.
2178 */
2179
2180 const MDL_lock::MDL_lock_strategy MDL_lock::m_scoped_lock_strategy =
2181 {
2182 /**
2183 Compatibility (or rather "incompatibility") matrices for scoped metadata
2184 lock. Arrays of bitmaps which elements specify which granted/waiting locks
2185 are incompatible with type of lock being requested.
2186
2187 The first array specifies if particular type of request can be satisfied
2188 if there is granted scoped lock of certain type.
2189
2190 | Type of active |
2191 Request | scoped lock |
2192 type | IS(*) IX S X |
2193 ---------+------------------+
2194 IS | + + + + |
2195 IX | + + - - |
2196 S | + - + - |
2197 X | + - - - |
2198
2199 Here: "+" -- means that request can be satisfied
2200 "-" -- means that request can't be satisfied and should wait
2201
2202 (*) Since intention shared scoped locks are compatible with all other
2203 type of locks we don't even have any accounting for them.
2204
2205 Note that relation between scoped locks and objects locks requested
2206 by statement is not straightforward and is therefore fully defined
2207 by SQL-layer.
2208 For example, in order to support global read lock implementation
2209 SQL-layer acquires IX lock in GLOBAL namespace for each statement
2210 that can modify metadata or data (i.e. for each statement that
2211 needs SW, SU, SNW, SNRW or X object locks). OTOH, to ensure that
2212 DROP DATABASE works correctly with concurrent DDL, IX metadata locks
2213 in SCHEMA namespace are acquired for DDL statements which can update
2214 metadata in the schema (i.e. which acquire SU, SNW, SNRW and X locks
2215 on schema objects) and aren't acquired for DML.
2216 */
2217 {
2218 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED),
2219 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_INTENTION_EXCLUSIVE),
2220 0, 0, 0, 0, 0, 0, 0, 0,
2221 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED) |
2222 MDL_BIT(MDL_INTENTION_EXCLUSIVE)
2223 },
2224 /**
2225 Each array in the next group specifies if a particular type of request can
2226 be satisfied if there is already a waiting request for the scoped lock of
2227 a certain type. I.e. each array specifies a matrice with priorities for
2228 different lock types.
2229
2230 Scoped locks only use the first array which represents the "default"
2231 priority matrix. The remaing 3 matrices are not relevant for them.
2232
2233 | Pending |
2234 Request | scoped lock |
2235 type | IS(*) IX S X |
2236 ---------+-----------------+
2237 IS | + + + + |
2238 IX | + + - - |
2239 S | + + + - |
2240 X | + + + + |
2241
2242 Here the meaning of "+", "-" and (*) is the same as above.
2243 */
2244 {
2245 {
2246 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED),
2247 MDL_BIT(MDL_EXCLUSIVE), 0, 0, 0, 0, 0, 0, 0, 0, 0
2248 },
2249 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
2250 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
2251 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2252 },
2253 /**
2254 Array of increments for "unobtrusive" types of lock requests for scoped
2255 locks.
2256
2257 @sa MDL_lock::get_unobtrusive_lock_increment().
2258
2259 For scoped locks:
2260 - "unobtrusive" types: IX
2261 - "obtrusive" types: X and S
2262
2263 We encode number of IX locks acquired using "fast path" in bits 0 .. 59
2264 of MDL_lock::m_fast_path_state.
2265 */
2266 { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
2267 /*
2268 In scoped locks, only IX lock request would starve because of X/S.
2269 But that is practically a very rare case. So we don't apply the
2270 max_write_lock_count limit to them.
2271 */
2272 false,
2273 /*
2274 Scoped locks doesn't require notification of owners of conflicting
2275 locks for any type of requests. Hence 'm_needs_notification' is NULL.
2276 */
2277 NULL,
2278 /*
2279 For the same reason, 'm_notify_conflicting_locks' is NULL for scoped locks.
2280 */
2281 NULL,
2282 &MDL_lock::scoped_lock_fast_path_granted_bitmap,
2283 /* Scoped locks never require connection check. */
2284 NULL
2285 };
2286
2287
2288 /**
2289 Strategy instance for per-object locks.
2290 Supports all locked modes except INTENTION EXCLUSIVE locks.
2291 */
2292
2293 const MDL_lock::MDL_lock_strategy MDL_lock::m_object_lock_strategy =
2294 {
2295 /**
2296 Compatibility (or rather "incompatibility") matrices for per-object
2297 metadata lock. Arrays of bitmaps which elements specify which granted/
2298 waiting locks are incompatible with type of lock being requested.
2299
2300 The first array specifies if particular type of request can be satisfied
2301 if there is granted lock of certain type.
2302
2303 Request | Granted requests for lock |
2304 type | S SH SR SW SWLP SU SRO SNW SNRW X |
2305 ----------+---------------------------------------------+
2306 S | + + + + + + + + + - |
2307 SH | + + + + + + + + + - |
2308 SR | + + + + + + + + - - |
2309 SW | + + + + + + - - - - |
2310 SWLP | + + + + + + - - - - |
2311 SU | + + + + + - + - - - |
2312 SRO | + + + - - + + + - - |
2313 SNW | + + + - - - + - - - |
2314 SNRW | + + - - - - - - - - |
2315 X | - - - - - - - - - - |
2316
2317 Here: "+" -- means that request can be satisfied
2318 "-" -- means that request can't be satisfied and should wait
2319
2320 @note In cases then current context already has "stronger" type
2321 of lock on the object it will be automatically granted
2322 thanks to usage of the MDL_context::find_ticket() method.
2323
2324 @note IX locks are excluded since they are not used for per-object
2325 metadata locks.
2326 */
2327 {
2328 0,
2329 MDL_BIT(MDL_EXCLUSIVE),
2330 MDL_BIT(MDL_EXCLUSIVE),
2331 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
2332 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2333 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
2334 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2335 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
2336 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2337 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE),
2338 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2339 MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO) | MDL_BIT(MDL_SHARED_WRITE),
2340 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2341 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE) |
2342 MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO) | MDL_BIT(MDL_SHARED_WRITE),
2343 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2344 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY) |
2345 MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO) |
2346 MDL_BIT(MDL_SHARED_WRITE) | MDL_BIT(MDL_SHARED_READ),
2347 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2348 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY) |
2349 MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO) |
2350 MDL_BIT(MDL_SHARED_WRITE) | MDL_BIT(MDL_SHARED_READ) |
2351 MDL_BIT(MDL_SHARED_HIGH_PRIO) | MDL_BIT(MDL_SHARED)
2352 },
2353 /**
2354 Each array in the next group specifies if a particular type of request can
2355 be satisfied if there is a waiting request for the same lock of a certain
2356 type. In other words each array specifies a priority matrix for different
2357 lock types.
2358
2359 We use each of the arrays depending on whether the number of successively
2360 granted "piglet" and "hog" lock requests exceed the max_write_lock_count
2361 threshold. This is necessary to avoid high priority lock requests starving
2362 out requests with lower priority.
2363
2364 The first array in the group is used in default situation when both
2365 MDL_lock::m_piglet_lock_count and MDL_lock::m_hog_lock_count don't exceed
2366 the threshold.
2367
2368 A priority matrice specified by it looks like:
2369
2370 Request | Pending requests for lock |
2371 type | S SH SR SW SWLP SU SRO SNW SNRW X |
2372 ----------+--------------------------------------------+
2373 S | + + + + + + + + + - |
2374 SH | + + + + + + + + + + |
2375 SR | + + + + + + + + - - |
2376 SW | + + + + + + + - - - |
2377 SWLP | + + + + + + - - - - |
2378 SU | + + + + + + + + + - |
2379 SRO | + + + - + + + + - - |
2380 SNW | + + + + + + + + + - |
2381 SNRW | + + + + + + + + + - |
2382 X | + + + + + + + + + + |
2383
2384 Invariant [INV2]: for all priority matrices, if A is the set of
2385 incompatible waiting requests for a given request and B is the set
2386 of incompatible granted requests for the same request, then A will
2387 always be a subset of B. This means that moving a lock from waiting
2388 to granted state doesn't unblock additional requests.
2389 MDL_lock::reschedule_waiters() code relies on this.
2390 */
2391 {
2392 {
2393 0,
2394 MDL_BIT(MDL_EXCLUSIVE),
2395 0,
2396 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
2397 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2398 MDL_BIT(MDL_SHARED_NO_WRITE),
2399 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2400 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
2401 MDL_BIT(MDL_EXCLUSIVE),
2402 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2403 MDL_BIT(MDL_SHARED_WRITE),
2404 MDL_BIT(MDL_EXCLUSIVE),
2405 MDL_BIT(MDL_EXCLUSIVE),
2406 0
2407 },
2408 /**
2409 The second array in the group is used when the number of successively
2410 granted "piglet" (SW) locks exceeds max_write_lock_count.
2411
2412 It is the same matrix as in the first case but with the SW lock type
2413 having lower priority than the SRO lock type.
2414 */
2415 {
2416 0,
2417 MDL_BIT(MDL_EXCLUSIVE),
2418 0,
2419 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
2420 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2421 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
2422 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2423 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
2424 MDL_BIT(MDL_EXCLUSIVE),
2425 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE),
2426 MDL_BIT(MDL_EXCLUSIVE),
2427 MDL_BIT(MDL_EXCLUSIVE),
2428 0
2429 },
2430 /**
2431 The third array in the group is used when the number of successively
2432 granted "hog" (SNW, SNRW, X) locks exceeds max_write_lock_count.
2433
2434 In this case S, SH, SR, SW, SNRW, SRO and SU locks types have
2435 priority over all "hog" types.
2436 */
2437 {
2438 0,
2439 0,
2440 0,
2441 0,
2442 0,
2443 MDL_BIT(MDL_SHARED_READ_ONLY),
2444 0,
2445 MDL_BIT(MDL_SHARED_WRITE),
2446 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_UPGRADABLE) |
2447 MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO) | MDL_BIT(MDL_SHARED_WRITE),
2448 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_READ_ONLY) |
2449 MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO) |
2450 MDL_BIT(MDL_SHARED_WRITE) | MDL_BIT(MDL_SHARED_READ),
2451 static_cast<bitmap_t>(~MDL_OBJECT_HOG_LOCK_TYPES)
2452 },
2453 /**
2454 The fourth array in the group is used when both the number of successively
2455 granted "piglet" (SW) and the number of successively granted "hog"
2456 (SNW, SNRW, X) locks exceed max_write_lock_count.
2457
2458 This matrice prefers SRO locks over SW/SWLP locks. And non-"hog" locks
2459 other than SW/SWLP over "hog" locks.
2460
2461 Note that the fact that "hog" locks have the same priority vs SW/SWLP
2462 locks as in the default matrice (#0) is important and is relied upon in
2463 MDL_lock::reschedule_waiters(). This is invariant [INV3].
2464 */
2465 {
2466 0,
2467 0,
2468 0,
2469 0,
2470 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2471 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
2472 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
2473 MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY),
2474 0,
2475 0,
2476 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_UPGRADABLE),
2477 MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_READ_ONLY) |
2478 MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_READ),
2479 static_cast<bitmap_t>(~(MDL_OBJECT_HOG_LOCK_TYPES |
2480 MDL_BIT(MDL_SHARED_WRITE) |
2481 MDL_BIT(MDL_SHARED_WRITE_LOW_PRIO)))
2482 }
2483 },
2484 /**
2485 Array of increments for "unobtrusive" types of lock requests for per-object
2486 locks.
2487
2488 @sa MDL_lock::get_unobtrusive_lock_increment().
2489
2490 For per-object locks:
2491 - "unobtrusive" types: S, SH, SR and SW
2492 - "obtrusive" types: SU, SRO, SNW, SNRW, X
2493
2494 Number of locks acquired using "fast path" are encoded in the following
2495 bits of MDL_lock::m_fast_path_state:
2496
2497 - bits 0 .. 19 - S and SH (we don't differentiate them once acquired)
2498 - bits 20 .. 39 - SR
2499 - bits 40 .. 59 - SW and SWLP (we don't differentiate them once acquired)
2500
2501 Overflow is not an issue as we are unlikely to support more than 2^20 - 1
2502 concurrent connections in foreseeable future.
2503
2504 This encoding defines the below contents of increment array.
2505 */
2506 { 0, 1, 1, 1ULL << 20, 1ULL << 40, 1ULL << 40, 0, 0, 0, 0, 0 },
2507 /*
2508 To prevent starvation, "hog" and "piglet" lock types are only granted
2509 max_write_lock_count times in a row while conflicting lock types are
2510 waiting.
2511 */
2512 true,
2513 &MDL_lock::object_lock_needs_notification,
2514 &MDL_lock::object_lock_notify_conflicting_locks,
2515 &MDL_lock::object_lock_fast_path_granted_bitmap,
2516 &MDL_lock::object_lock_needs_connection_check
2517 };
2518
2519
2520 /**
2521 Check if request for the metadata lock can be satisfied given its
2522 current state.
2523
2524 @param type_arg The requested lock type.
2525 @param requestor_ctx The MDL context of the requestor.
2526
2527 @retval TRUE Lock request can be satisfied
2528 @retval FALSE There is some conflicting lock.
2529
2530 @note In cases then current context already has "stronger" type
2531 of lock on the object it will be automatically granted
2532 thanks to usage of the MDL_context::find_ticket() method.
2533 */
2534
2535 bool
can_grant_lock(enum_mdl_type type_arg,const MDL_context * requestor_ctx) const2536 MDL_lock::can_grant_lock(enum_mdl_type type_arg,
2537 const MDL_context *requestor_ctx) const
2538 {
2539 bool can_grant= FALSE;
2540 bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg];
2541 bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg];
2542
2543 /*
2544 New lock request can be satisfied iff:
2545 - There are no incompatible types of satisfied requests
2546 in other contexts
2547 - There are no waiting requests which have higher priority
2548 than this request.
2549 */
2550 if (!(m_waiting.bitmap() & waiting_incompat_map))
2551 {
2552 if (! (fast_path_granted_bitmap() & granted_incompat_map))
2553 {
2554 if (! (m_granted.bitmap() & granted_incompat_map))
2555 can_grant= TRUE;
2556 else
2557 {
2558 Ticket_iterator it(m_granted);
2559 MDL_ticket *ticket;
2560
2561 /*
2562 There is an incompatible lock. Check that it belongs to some
2563 other context.
2564
2565 If we are trying to acquire "unobtrusive" type of lock then the
2566 confliciting lock must be from "obtrusive" set, therefore it should
2567 have been acquired using "slow path" and should be present in
2568 m_granted list.
2569
2570 If we are trying to acquire "obtrusive" type of lock then it can be
2571 either another "obtrusive" lock or "unobtrusive" type of lock
2572 acquired on "slow path" (can't be "unobtrusive" lock on fast path
2573 because of surrounding if-statement). In either case it should be
2574 present in m_granted list.
2575 */
2576 while ((ticket= it++))
2577 {
2578 if (ticket->get_ctx() != requestor_ctx &&
2579 ticket->is_incompatible_when_granted(type_arg))
2580 break;
2581 }
2582 if (ticket == NULL) /* Incompatible locks are our own. */
2583 can_grant= TRUE;
2584 }
2585 }
2586 else
2587 {
2588 /*
2589 Our lock request conflicts with one of granted "fast path" locks:
2590
2591 This means that we are trying to acquire "obtrusive" lock and:
2592 a) Either we are called from MDL_context::try_acquire_lock_impl()
2593 and then all "fast path" locks belonging to this context were
2594 materialized (as we do for "obtrusive" locks).
2595 b) Or we are called from MDL_lock::reschedule_waiters() then
2596 this context is waiting for this request and all its "fast
2597 path" locks were materialized before the wait.
2598
2599 The above means that conflicting granted "fast path" lock cannot
2600 belong to us and our request cannot be satisfied.
2601 */
2602 }
2603 }
2604 return can_grant;
2605 }
2606
2607
2608 /**
2609 Return the first MDL_context which owns the lock.
2610
2611 @return Pointer to the first MDL_context which has acquired the lock
2612 NULL if there are no such contexts.
2613
2614 @note This method works properly only for locks acquired using
2615 "slow" path. It won't return context if it has used "fast"
2616 path to acquire the lock.
2617 */
2618
2619 inline MDL_context *
get_lock_owner() const2620 MDL_lock::get_lock_owner() const
2621 {
2622 Ticket_iterator it(m_granted);
2623 MDL_ticket *ticket;
2624
2625 if ((ticket= it++))
2626 return ticket->get_ctx();
2627 return NULL;
2628 }
2629
2630
2631 /** Remove a ticket from waiting or pending queue and wakeup up waiters. */
2632
remove_ticket(MDL_context * ctx,LF_PINS * pins,Ticket_list MDL_lock::* list,MDL_ticket * ticket)2633 void MDL_lock::remove_ticket(MDL_context *ctx, LF_PINS *pins,
2634 Ticket_list MDL_lock::*list,
2635 MDL_ticket *ticket)
2636 {
2637 bool is_obtrusive= is_obtrusive_lock(ticket->get_type());
2638 bool is_singleton= mdl_locks.is_lock_object_singleton(&key);
2639
2640 mysql_prlock_wrlock(&m_rwlock);
2641
2642 DEBUG_SYNC(current_thd, "mdl_lock_remove_ticket_m_rwlock_locked");
2643
2644 (this->*list).remove_ticket(ticket);
2645
2646 /*
2647 If we are removing "obtrusive" type of request either from granted or
2648 waiting lists we need to decrement "obtrusive" requests counter.
2649 Once last ticket for "obtrusive" lock is removed we should clear
2650 HAS_OBTRUSIVE flag in m_fast_path_state as well.
2651 */
2652 bool last_obtrusive= is_obtrusive &&
2653 ((--m_obtrusive_locks_granted_waiting_count) == 0);
2654 /*
2655 If both m_granted and m_waiting lists become empty as result we also
2656 need to clear HAS_SLOW_PATH flag in m_fast_path_state.
2657 */
2658 bool last_slow_path= m_granted.is_empty() && m_waiting.is_empty();
2659 bool last_use= false;
2660
2661 if (last_slow_path || last_obtrusive)
2662 {
2663 fast_path_state_t old_state= m_fast_path_state;
2664 fast_path_state_t new_state;
2665 do
2666 {
2667 new_state= old_state;
2668 if (last_slow_path)
2669 new_state&= ~MDL_lock::HAS_SLOW_PATH;
2670 if (last_obtrusive)
2671 new_state&= ~MDL_lock::HAS_OBTRUSIVE;
2672 }
2673 while (! fast_path_state_cas(&old_state, new_state));
2674
2675 /*
2676 We don't have any "fast" or "slow" path locks. MDL_lock object becomes
2677 unused so unused objects counter needs to be incremented.
2678 */
2679 if (new_state == 0)
2680 last_use= true;
2681 }
2682
2683
2684 if (last_slow_path)
2685 {
2686 /*
2687 We might end-up with the last waiting ticket being removed and non-0
2688 m_hog_lock_count/m_piglet_lock_count in the following situation:
2689
2690 1) There is a granted "hog"/"piglet" lock blocking a lower priority lock
2691 request.
2692 2) The lower priority lock request is timed out or killed. It is not yet
2693 removed from waiters list and bitmap.
2694 3) The "Hog"/"piglet" lock is released. Its reschedule_waiters() call
2695 will still see the pending lower priority lock so it won't reset
2696 the m_hog_lock_count/m_piglet_lock_count counters.
2697 4) MDL_lock::remove_ticket() is called for the timed out/killed
2698 lower priority ticket. Which turns out to be the last ticket
2699 for this lock.
2700
2701 Hence we need to reset these counters here.
2702 */
2703 m_hog_lock_count= 0;
2704 m_piglet_lock_count= 0;
2705 m_current_waiting_incompatible_idx= 0;
2706 }
2707 else
2708 {
2709 /*
2710 There can be some contexts waiting to acquire a lock
2711 which now might be able to do it. Grant the lock to
2712 them and wake them up!
2713
2714 We always try to reschedule locks, since there is no easy way
2715 (i.e. by looking at the bitmaps) to find out whether it is
2716 required or not.
2717 In a general case, even when the queue's bitmap is not changed
2718 after removal of the ticket, there is a chance that some request
2719 can be satisfied (due to the fact that a granted request
2720 reflected in the bitmap might belong to the same context as a
2721 pending request).
2722 */
2723 reschedule_waiters();
2724 }
2725 mysql_prlock_unlock(&m_rwlock);
2726
2727 /* Don't count singleton MDL_lock objects as unused. */
2728 if (last_use && ! is_singleton)
2729 mdl_locks.lock_object_unused(ctx, pins);
2730 }
2731
2732
2733 /**
2734 Check if we have any pending locks which conflict with existing
2735 shared lock.
2736
2737 @pre The ticket must match an acquired lock.
2738
2739 @return TRUE if there is a conflicting lock request, FALSE otherwise.
2740 */
2741
has_pending_conflicting_lock(enum_mdl_type type)2742 bool MDL_lock::has_pending_conflicting_lock(enum_mdl_type type)
2743 {
2744 bool result;
2745
2746 mysql_mutex_assert_not_owner(&LOCK_open);
2747
2748 mysql_prlock_rdlock(&m_rwlock);
2749 result= (m_waiting.bitmap() & incompatible_granted_types_bitmap()[type]);
2750 mysql_prlock_unlock(&m_rwlock);
2751 return result;
2752 }
2753
2754
~MDL_wait_for_graph_visitor()2755 MDL_wait_for_graph_visitor::~MDL_wait_for_graph_visitor()
2756 {
2757 }
2758
2759
~MDL_wait_for_subgraph()2760 MDL_wait_for_subgraph::~MDL_wait_for_subgraph()
2761 {
2762 }
2763
2764 /**
2765 Check if ticket represents metadata lock of "stronger" or equal type
2766 than specified one. I.e. if metadata lock represented by ticket won't
2767 allow any of locks which are not allowed by specified type of lock.
2768
2769 @return TRUE if ticket has stronger or equal type
2770 FALSE otherwise.
2771 */
2772
has_stronger_or_equal_type(enum_mdl_type type) const2773 bool MDL_ticket::has_stronger_or_equal_type(enum_mdl_type type) const
2774 {
2775 const MDL_lock::bitmap_t *
2776 granted_incompat_map= m_lock->incompatible_granted_types_bitmap();
2777
2778 return ! (granted_incompat_map[type] & ~(granted_incompat_map[m_type]));
2779 }
2780
2781
is_incompatible_when_granted(enum_mdl_type type) const2782 bool MDL_ticket::is_incompatible_when_granted(enum_mdl_type type) const
2783 {
2784 return (MDL_BIT(m_type) &
2785 m_lock->incompatible_granted_types_bitmap()[type]);
2786 }
2787
2788
2789 bool
is_incompatible_when_waiting(enum_mdl_type type) const2790 MDL_ticket::is_incompatible_when_waiting(enum_mdl_type type) const
2791 {
2792 return (MDL_BIT(m_type) &
2793 m_lock->incompatible_waiting_types_bitmap()[type]);
2794 }
2795
2796
2797 /**
2798 Check whether the context already holds a compatible lock ticket
2799 on an object.
2800 Start searching from list of locks for the same duration as lock
2801 being requested. If not look at lists for other durations.
2802
2803 @param mdl_request Lock request object for lock to be acquired
2804 @param[out] result_duration Duration of lock which was found.
2805
2806 @note Tickets which correspond to lock types "stronger" than one
2807 being requested are also considered compatible.
2808
2809 @return A pointer to the lock ticket for the object or NULL otherwise.
2810 */
2811
2812 MDL_ticket *
find_ticket(MDL_request * mdl_request,enum_mdl_duration * result_duration)2813 MDL_context::find_ticket(MDL_request *mdl_request,
2814 enum_mdl_duration *result_duration)
2815 {
2816 MDL_ticket *ticket;
2817 int i;
2818
2819 for (i= 0; i < MDL_DURATION_END; i++)
2820 {
2821 enum_mdl_duration duration= (enum_mdl_duration)((mdl_request->duration+i) %
2822 MDL_DURATION_END);
2823 Ticket_iterator it(m_tickets[duration]);
2824
2825 while ((ticket= it++))
2826 {
2827 if (mdl_request->key.is_equal(&ticket->m_lock->key) &&
2828 ticket->has_stronger_or_equal_type(mdl_request->type))
2829 {
2830 *result_duration= duration;
2831 return ticket;
2832 }
2833 }
2834 }
2835 return NULL;
2836 }
2837
2838
2839 /**
2840 Try to acquire one lock.
2841
2842 Unlike exclusive locks, shared locks are acquired one by
2843 one. This is interface is chosen to simplify introduction of
2844 the new locking API to the system. MDL_context::try_acquire_lock()
2845 is currently used from open_table(), and there we have only one
2846 table to work with.
2847
2848 This function may also be used to try to acquire an exclusive
2849 lock on a destination table, by ALTER TABLE ... RENAME.
2850
2851 Returns immediately without any side effect if encounters a lock
2852 conflict. Otherwise takes the lock.
2853
2854 @param mdl_request [in/out] Lock request object for lock to be acquired
2855
2856 @retval FALSE Success. The lock may have not been acquired.
2857 Check the ticket, if it's NULL, a conflicting lock
2858 exists.
2859 @retval TRUE Out of resources, an error has been reported.
2860 */
2861
2862 bool
try_acquire_lock(MDL_request * mdl_request)2863 MDL_context::try_acquire_lock(MDL_request *mdl_request)
2864 {
2865 MDL_ticket *ticket;
2866
2867 if (try_acquire_lock_impl(mdl_request, &ticket))
2868 return TRUE;
2869
2870 if (! mdl_request->ticket)
2871 {
2872 /*
2873 Our attempt to acquire lock without waiting has failed.
2874 Let us release resources which were acquired in the process.
2875
2876 We don't need to count MDL_lock object as unused and possibly
2877 delete it here because:
2878 - Either there was a conflicting ticket in MDL_lock::m_granted/
2879 m_waiting lists during our call to MDL_lock::can_grant_lock().
2880 This ticket can't go away while MDL_lock::m_rwlock is held.
2881 - Or we have tried to acquire an "obtrusive" lock and there was
2882 a conflicting "fast path" lock in MDL_lock::m_fast_path_state
2883 counter during our call to MDL_lock::can_grant_lock().
2884 In this case HAS_OBTRUSIVE lock flag should have been set before
2885 call to MDL_lock::can_grant_lock() so release of this "fast path"
2886 lock will have to take slow path (see release_lock() and invariant
2887 [INV1]). This means that conflicting "fast path" lock can't go
2888 away until MDL_lock::m_rwlock is released or HAS_OBSTRUSIVE flag
2889 is cleared. In the latter case counting MDL_lock object as unused
2890 is responsibility of thread which is decrementing "fast path" lock
2891 counter. MDL_lock object can't be deleted under out feet since
2892 thread doing deletion needs to acquire MDL_lock::m_rwlock first.
2893 */
2894 MDL_lock *lock= ticket->m_lock;
2895
2896 bool last_obtrusive= lock->is_obtrusive_lock(mdl_request->type) &&
2897 ((--lock->m_obtrusive_locks_granted_waiting_count) == 0);
2898 bool last_slow_path= lock->m_granted.is_empty() &&
2899 lock->m_waiting.is_empty();
2900
2901 if (last_slow_path || last_obtrusive)
2902 {
2903 MDL_lock::fast_path_state_t old_state= lock->m_fast_path_state;
2904 MDL_lock::fast_path_state_t new_state;
2905 do
2906 {
2907 new_state= old_state;
2908 if (last_slow_path)
2909 new_state&= ~MDL_lock::HAS_SLOW_PATH;
2910 if (last_obtrusive)
2911 new_state&= ~MDL_lock::HAS_OBTRUSIVE;
2912 }
2913 while (! lock->fast_path_state_cas(&old_state, new_state));
2914 }
2915
2916 mysql_prlock_unlock(&lock->m_rwlock);
2917
2918 /*
2919 If SEs were notified about impending lock acquisition, the failure
2920 to acquire it requires the same notification as lock release.
2921 */
2922 if (ticket->m_hton_notified)
2923 {
2924 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::POST_RELEASE_NOTIFY);
2925 m_owner->notify_hton_post_release_exclusive(&mdl_request->key);
2926 }
2927
2928 MDL_ticket::destroy(ticket);
2929 }
2930
2931 return FALSE;
2932 }
2933
2934
2935 /**
2936 "Materialize" requests for locks which were satisfied using
2937 "fast path" by properly including them into corresponding
2938 MDL_lock::m_granted bitmaps/lists and removing it from
2939 packed counter in MDL_lock::m_fast_path_state.
2940
2941 @note In future we might optimize this method if necessary,
2942 for example, by keeping pointer to first "fast path"
2943 ticket.
2944 */
2945
materialize_fast_path_locks()2946 void MDL_context::materialize_fast_path_locks()
2947 {
2948 int i;
2949
2950 for (i= 0; i < MDL_DURATION_END; i++)
2951 {
2952 Ticket_iterator it(m_tickets[(enum_mdl_duration)i]);
2953 MDL_ticket *ticket;
2954
2955 while ((ticket= it++))
2956 {
2957 if (ticket->m_is_fast_path)
2958 {
2959 MDL_lock *lock= ticket->m_lock;
2960 MDL_lock::fast_path_state_t unobtrusive_lock_increment=
2961 lock->get_unobtrusive_lock_increment(ticket->get_type());
2962 ticket->m_is_fast_path= false;
2963 mysql_prlock_wrlock(&lock->m_rwlock);
2964 lock->m_granted.add_ticket(ticket);
2965 /*
2966 Atomically decrement counter in MDL_lock::m_fast_path_state.
2967 This needs to happen under protection of MDL_lock::m_rwlock to make
2968 it atomic with addition of ticket to MDL_lock::m_granted list and
2969 to enforce invariant [INV1].
2970 */
2971 MDL_lock::fast_path_state_t old_state= lock->m_fast_path_state;
2972 while (! lock->fast_path_state_cas(&old_state,
2973 ((old_state - unobtrusive_lock_increment) |
2974 MDL_lock::HAS_SLOW_PATH)))
2975 { }
2976 mysql_prlock_unlock(&lock->m_rwlock);
2977 }
2978 }
2979 }
2980 }
2981
2982
2983 /**
2984 Auxiliary method for acquiring lock without waiting.
2985
2986 @param mdl_request [in/out] Lock request object for lock to be acquired
2987 @param out_ticket [out] Ticket for the request in case when lock
2988 has not been acquired.
2989
2990 @retval FALSE Success. The lock may have not been acquired.
2991 Check MDL_request::ticket, if it's NULL, a conflicting
2992 lock exists. In this case "out_ticket" out parameter
2993 points to ticket which was constructed for the request.
2994 MDL_ticket::m_lock points to the corresponding MDL_lock
2995 object and MDL_lock::m_rwlock write-locked.
2996 @retval TRUE Out of resources, an error has been reported.
2997 */
2998
2999 bool
try_acquire_lock_impl(MDL_request * mdl_request,MDL_ticket ** out_ticket)3000 MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
3001 MDL_ticket **out_ticket)
3002 {
3003 MDL_lock *lock;
3004 MDL_key *key= &mdl_request->key;
3005 MDL_ticket *ticket;
3006 enum_mdl_duration found_duration;
3007 MDL_lock::fast_path_state_t unobtrusive_lock_increment;
3008 bool force_slow;
3009 bool pinned;
3010
3011 assert(mdl_request->ticket == NULL);
3012
3013 /* Don't take chances in production. */
3014 mdl_request->ticket= NULL;
3015 mysql_mutex_assert_not_owner(&LOCK_open);
3016
3017 /*
3018 Check whether the context already holds a shared lock on the object,
3019 and if so, grant the request.
3020 */
3021 if ((ticket= find_ticket(mdl_request, &found_duration)))
3022 {
3023 assert(ticket->m_lock);
3024 assert(ticket->has_stronger_or_equal_type(mdl_request->type));
3025 /*
3026 If the request is for a transactional lock, and we found
3027 a transactional lock, just reuse the found ticket.
3028
3029 It's possible that we found a transactional lock,
3030 but the request is for a HANDLER lock. In that case HANDLER
3031 code will clone the ticket (see below why it's needed).
3032
3033 If the request is for a transactional lock, and we found
3034 a HANDLER lock, create a copy, to make sure that when user
3035 does HANDLER CLOSE, the transactional lock is not released.
3036
3037 If the request is for a handler lock, and we found a
3038 HANDLER lock, also do the clone. HANDLER CLOSE for one alias
3039 should not release the lock on the table HANDLER opened through
3040 a different alias.
3041 */
3042 mdl_request->ticket= ticket;
3043 if ((found_duration != mdl_request->duration ||
3044 mdl_request->duration == MDL_EXPLICIT) &&
3045 clone_ticket(mdl_request))
3046 {
3047 /* Clone failed. */
3048 mdl_request->ticket= NULL;
3049 return TRUE;
3050 }
3051 return FALSE;
3052 }
3053
3054 /*
3055 Prepare context for lookup in MDL_map container by allocating pins
3056 if necessary. This also ensures that this MDL_context has pins allocated
3057 and ready for future attempts elements from MDL_map container (which
3058 might happen during lock release).
3059 */
3060 if (fix_pins())
3061 return TRUE;
3062
3063 if (!(ticket= MDL_ticket::create(this, mdl_request->type
3064 #ifndef NDEBUG
3065 , mdl_request->duration
3066 #endif
3067 )))
3068 return TRUE;
3069
3070 /*
3071 Get increment for "fast path" or indication that this is
3072 request for "obtrusive" type of lock outside of critical section.
3073 */
3074 unobtrusive_lock_increment=
3075 MDL_lock::get_unobtrusive_lock_increment(mdl_request);
3076
3077 /*
3078 If this "obtrusive" type we have to take "slow path".
3079 If this context has open HANDLERs we have to take "slow path"
3080 as well for MDL_object_lock::notify_conflicting_locks() to work
3081 properly.
3082 */
3083 force_slow= ! unobtrusive_lock_increment || m_needs_thr_lock_abort;
3084
3085 /*
3086 If "obtrusive" lock is requested we need to "materialize" all fast
3087 path tickets, so MDL_lock::can_grant_lock() can safely assume
3088 that all granted "fast path" locks belong to different context.
3089 */
3090 if (! unobtrusive_lock_increment)
3091 materialize_fast_path_locks();
3092
3093 assert(ticket->m_psi == NULL);
3094 ticket->m_psi= mysql_mdl_create(ticket, key,
3095 mdl_request->type,
3096 mdl_request->duration,
3097 MDL_ticket::PENDING,
3098 mdl_request->m_src_file,
3099 mdl_request->m_src_line);
3100
3101 /*
3102 We need to notify/get permission from storage engines before acquiring
3103 X lock if it is requested in one of namespaces interesting for SEs.
3104 */
3105 if (mdl_request->type == MDL_EXCLUSIVE &&
3106 MDL_lock::needs_hton_notification(key->mdl_namespace()))
3107 {
3108 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY);
3109
3110 bool victimized;
3111 if (m_owner->notify_hton_pre_acquire_exclusive(key, &victimized))
3112 {
3113 MDL_ticket::destroy(ticket);
3114 my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, MYF(0));
3115 return TRUE;
3116 }
3117 ticket->m_hton_notified= true;
3118
3119 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING);
3120 }
3121
3122 retry:
3123 /*
3124 The below call pins pointer to returned MDL_lock object (unless
3125 it is the singleton object for GLOBAL or COMMIT namespaces).
3126 */
3127 if (!(lock= mdl_locks.find_or_insert(m_pins, key, &pinned)))
3128 {
3129 /*
3130 If SEs were notified about impending lock acquisition, the failure
3131 to acquire it requires the same notification as lock release.
3132 */
3133 if (ticket->m_hton_notified)
3134 {
3135 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::POST_RELEASE_NOTIFY);
3136 m_owner->notify_hton_post_release_exclusive(key);
3137 }
3138 MDL_ticket::destroy(ticket);
3139 return TRUE;
3140 }
3141
3142 /*
3143 Code counting unused MDL_lock objects below assumes that object is not
3144 pinned iff it is a singleton.
3145 */
3146 assert(mdl_locks.is_lock_object_singleton(key) == !pinned);
3147
3148 if (! force_slow)
3149 {
3150 /*
3151 "Fast path".
3152
3153 Hurray! We are acquring "unobtrusive" type of lock and not forced
3154 to take "slow path" because of open HANDLERs.
3155
3156 Let us do a few checks first to figure out if we really can acquire
3157 lock using "fast path".
3158
3159 Since the MDL_lock object is pinned at this point (or it is the
3160 singleton) we can access its members without risk of it getting deleted
3161 under out feet.
3162
3163 Ordinary read of MDL_lock::m_fast_path_state which we do here is OK as
3164 correctness of value returned by it will be anyway validated by atomic
3165 compare-and-swap which happens later.
3166 In theory, this algorithm will work correctly (but not very efficiently)
3167 if the read will return random values.
3168 In practice, it won't return values which are too out-of-date as the
3169 above call to MDL_map::find_or_insert() contains memory barrier.
3170 */
3171 MDL_lock::fast_path_state_t old_state= lock->m_fast_path_state;
3172 bool first_use;
3173
3174 do
3175 {
3176 /*
3177 Check if hash look-up returned object marked as destroyed or
3178 it was marked as such while it was pinned by us. If yes we
3179 need to unpin it and retry look-up.
3180 */
3181 if (old_state & MDL_lock::IS_DESTROYED)
3182 {
3183 if (pinned)
3184 lf_hash_search_unpin(m_pins);
3185 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_is_destroyed_fast_path");
3186 goto retry;
3187 }
3188
3189 /*
3190 Check that there are no granted/pending "obtrusive" locks and nobody
3191 even is about to try to check if such lock can be acquired.
3192
3193 In these cases we need to take "slow path".
3194 */
3195 if (old_state & MDL_lock::HAS_OBTRUSIVE)
3196 goto slow_path;
3197
3198 /*
3199 If m_fast_path_state doesn't have HAS_SLOW_PATH set and all "fast"
3200 path counters are 0 then we are about to use an unused MDL_lock
3201 object. We need to decrement unused objects counter eventually.
3202 */
3203 first_use= (old_state == 0);
3204
3205 /*
3206 Now we simply need to increment m_fast_path_state with a value which
3207 corresponds to type of our request (i.e. increment part this member
3208 which contains counter which corresponds to this type).
3209
3210 This needs to be done as atomical operation with the above checks,
3211 which is achieved by using atomic compare-and-swap.
3212
3213 @sa MDL_object_lock::m_unobtrusive_lock_increment for explanation
3214 why overflow is not an issue here.
3215 */
3216 }
3217 while (! lock->fast_path_state_cas(&old_state,
3218 old_state + unobtrusive_lock_increment));
3219
3220 /*
3221 Lock has been acquired. Since this can only be an "unobtrusive" lock and
3222 there were no active/pending requests for "obtrusive" locks, we don't need
3223 to care about "hog" and "piglet" locks and the max_write_lock_count
3224 threshold.
3225 */
3226
3227 if (pinned)
3228 lf_hash_search_unpin(m_pins);
3229
3230 /*
3231 Don't count singleton MDL_lock objects as used, use "pinned == false"
3232 as an indication of such objects.
3233 */
3234 if (first_use && pinned)
3235 mdl_locks.lock_object_used();
3236
3237 /*
3238 Since this MDL_ticket is not visible to any threads other than
3239 the current one, we can set MDL_ticket::m_lock member without
3240 protect of MDL_lock::m_rwlock. MDL_lock won't be deleted
3241 underneath our feet as MDL_lock::m_fast_path_state serves as
3242 reference counter in this case.
3243 */
3244 ticket->m_lock= lock;
3245 ticket->m_is_fast_path= true;
3246
3247 m_tickets[mdl_request->duration].push_front(ticket);
3248
3249 mdl_request->ticket= ticket;
3250
3251 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
3252 return FALSE;
3253 }
3254
3255 slow_path:
3256
3257 /*
3258 "Slow path".
3259
3260 Do full-blown check and list manipulation if necessary.
3261 */
3262 mysql_prlock_wrlock(&lock->m_rwlock);
3263
3264 /*
3265 First of all, let us check if hash look-up returned MDL_lock object which
3266 is marked as destroyed or was marked as such while it was pinned by us.
3267 If we have got such object we need to retry look-up.
3268
3269 We can use ordinary non-atomic read in this case as this flag is set under
3270 protection of MDL_lock::m_rwlock (we can get inconsistent data for other
3271 parts of m_fast_path_state due to concurrent atomic updates, but we don't
3272 care about them yet).
3273 */
3274 MDL_lock::fast_path_state_t state= lock->m_fast_path_state;
3275
3276 if (state & MDL_lock::IS_DESTROYED)
3277 {
3278 mysql_prlock_unlock(&lock->m_rwlock);
3279 /*
3280 We can't unpin object earlier as lf_hash_delete() might have been
3281 called for it already and so LF_ALLOCATOR is free to deallocate it
3282 once unpinned.
3283 */
3284 if (pinned)
3285 lf_hash_search_unpin(m_pins);
3286 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_is_destroyed_slow_path");
3287 goto retry;
3288 }
3289
3290 /*
3291 Object was not marked as destroyed. Since it can't be deleted from hash
3292 and deallocated until this happens we can unpin it and work with it safely
3293 while MDL_lock::m_rwlock is held.
3294 */
3295 if (pinned)
3296 lf_hash_search_unpin(m_pins);
3297
3298 /*
3299 When we try to acquire the first obtrusive lock for MDL_lock object we
3300 need to atomically set the HAS_OBTRUSIVE flag in m_fast_path_state before
3301 we call the MDL_lock::can_grant_lock() method.
3302 This is necessary to prevent concurrent fast path acquisitions from
3303 invalidating the results of this method.
3304 */
3305 bool first_obtrusive_lock= (unobtrusive_lock_increment == 0) &&
3306 ((lock->m_obtrusive_locks_granted_waiting_count++) == 0);
3307 bool first_use= false;
3308
3309 /*
3310 When we try to acquire the first "slow" path lock for MDL_lock object
3311 we also need to atomically set HAS_SLOW_PATH flag. It is OK to read
3312 HAS_SLOW_PATH non-atomically here since it can be only set under
3313 protection of MDL_lock::m_rwlock lock.
3314 */
3315 if (!(state & MDL_lock::HAS_SLOW_PATH) || first_obtrusive_lock)
3316 {
3317 do
3318 {
3319 /*
3320 If HAS_SLOW_PATH flag is not set and all "fast" path counters
3321 are zero we are about to use previously unused MDL_lock object.
3322 MDL_map::m_unused_lock_objects counter needs to be decremented
3323 eventually.
3324 */
3325 first_use= (state == 0);
3326 }
3327 while (! lock->fast_path_state_cas(&state,
3328 state | MDL_lock::HAS_SLOW_PATH |
3329 (first_obtrusive_lock ? MDL_lock::HAS_OBTRUSIVE: 0)));
3330 }
3331
3332 /*
3333 Don't count singleton MDL_lock objects as used, use "pinned == false"
3334 as an indication of such objects.
3335
3336 If the fact that we do this atomic decrement under MDL_lock::m_rwlock
3337 ever becomes bottleneck (which is unlikely) it can be safely moved
3338 outside of critical section.
3339 */
3340 if (first_use && pinned)
3341 mdl_locks.lock_object_used();
3342
3343 ticket->m_lock= lock;
3344
3345 if (lock->can_grant_lock(mdl_request->type, this))
3346 {
3347 lock->m_granted.add_ticket(ticket);
3348
3349 if (lock->is_affected_by_max_write_lock_count())
3350 {
3351 /*
3352 If we have acquired an higher-prio "piglet" or "hog" lock while there
3353 are pending lower priority locks, we need to increment the appropriate
3354 counter.
3355
3356 If one or both of these counters exceed the max_write_lock_count
3357 threshold, change priority matrice for this MDL_lock object.
3358 Reschedule waiters to avoid problems when the change of matrice
3359 happens concurrently to other thread acquiring a lower priority
3360 lock between its call to MDL_lock::can_grant_lock() and
3361 MDL_context::find_deadlock().
3362 */
3363 if (lock->count_piglets_and_hogs(mdl_request->type))
3364 lock->reschedule_waiters();
3365 }
3366
3367 mysql_prlock_unlock(&lock->m_rwlock);
3368
3369 m_tickets[mdl_request->duration].push_front(ticket);
3370
3371 mdl_request->ticket= ticket;
3372
3373 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
3374 }
3375 else
3376 *out_ticket= ticket;
3377
3378 return FALSE;
3379 }
3380
3381
3382 /**
3383 Create a copy of a granted ticket.
3384 This is used to make sure that HANDLER ticket
3385 is never shared with a ticket that belongs to
3386 a transaction, so that when we HANDLER CLOSE,
3387 we don't release a transactional ticket, and
3388 vice versa -- when we COMMIT, we don't mistakenly
3389 release a ticket for an open HANDLER.
3390
3391 @retval TRUE Out of memory.
3392 @retval FALSE Success.
3393 */
3394
3395 bool
clone_ticket(MDL_request * mdl_request)3396 MDL_context::clone_ticket(MDL_request *mdl_request)
3397 {
3398 MDL_ticket *ticket;
3399
3400 mysql_mutex_assert_not_owner(&LOCK_open);
3401
3402 /*
3403 Since in theory we can clone ticket belonging to a different context
3404 we need to prepare target context for possible attempts to release
3405 lock and thus possible removal of MDL_lock from MDL_map container.
3406 So we allocate pins to be able to work with this container if they
3407 are not allocated already.
3408 */
3409 if (fix_pins())
3410 return TRUE;
3411
3412 /*
3413 By submitting mdl_request->type to MDL_ticket::create()
3414 we effectively downgrade the cloned lock to the level of
3415 the request.
3416 */
3417 if (!(ticket= MDL_ticket::create(this, mdl_request->type
3418 #ifndef NDEBUG
3419 , mdl_request->duration
3420 #endif
3421 )))
3422 return TRUE;
3423
3424 assert(ticket->m_psi == NULL);
3425 ticket->m_psi= mysql_mdl_create(ticket,
3426 &mdl_request->key,
3427 mdl_request->type,
3428 mdl_request->duration,
3429 MDL_ticket::PENDING,
3430 mdl_request->m_src_file,
3431 mdl_request->m_src_line);
3432
3433 /* clone() is not supposed to be used to get a stronger lock. */
3434 assert(mdl_request->ticket->has_stronger_or_equal_type(ticket->m_type));
3435
3436
3437 /*
3438 If we are to clone exclusive lock in namespace requiring notification
3439 of storage engines we need to notify/get permission from SEs similarly
3440 to situation when lock acquired.
3441 */
3442 if (mdl_request->type == MDL_EXCLUSIVE &&
3443 MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace()))
3444 {
3445 assert(mdl_request->ticket->m_hton_notified);
3446
3447 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY);
3448
3449 bool victimized;
3450 if (m_owner->notify_hton_pre_acquire_exclusive(&mdl_request->key, &victimized))
3451 {
3452 MDL_ticket::destroy(ticket);
3453 my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, MYF(0));
3454 return TRUE;
3455 }
3456 ticket->m_hton_notified= true;
3457
3458 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING);
3459 }
3460
3461 ticket->m_lock= mdl_request->ticket->m_lock;
3462
3463 if (mdl_request->ticket->m_is_fast_path)
3464 {
3465 /*
3466 We are cloning ticket which was acquired on "fast path".
3467 Let us use "fast path" to create clone as well.
3468 */
3469 MDL_lock::fast_path_state_t unobtrusive_lock_increment=
3470 ticket->m_lock->get_unobtrusive_lock_increment(ticket->get_type());
3471
3472 /*
3473 "Obtrusive" type of lock can't be cloned from weaker, "unobtrusive"
3474 type of lock.
3475 */
3476 assert(unobtrusive_lock_increment != 0);
3477
3478 /*
3479 Increment of counter in MDL_lock::m_fast_path_state needs to happen here
3480 atomically and under protection of MDL_lock::m_rwlock in order to enforce
3481 invariant [INV1].
3482 */
3483 mysql_prlock_wrlock(&ticket->m_lock->m_rwlock);
3484 ticket->m_lock->fast_path_state_add(unobtrusive_lock_increment);
3485 mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
3486 ticket->m_is_fast_path= true;
3487 }
3488 else
3489 {
3490 /*
3491 We are cloning ticket which was acquired on "slow path".
3492 We will use "slow path" for new ticket as well. We also
3493 need to take into account if new ticket corresponds to
3494 "obtrusive" lock.
3495 */
3496 bool is_obtrusive= ticket->m_lock->is_obtrusive_lock(ticket->m_type);
3497 mysql_prlock_wrlock(&ticket->m_lock->m_rwlock);
3498 ticket->m_lock->m_granted.add_ticket(ticket);
3499 if (is_obtrusive)
3500 {
3501 /*
3502 We don't need to set HAS_OBTRUSIVE flag in MDL_lock::m_fast_path_state
3503 here as it is already set since the ticket being cloned already
3504 represents "obtrusive" lock for this MDL_lock object.
3505 */
3506 assert(ticket->m_lock->m_obtrusive_locks_granted_waiting_count != 0);
3507 ++ticket->m_lock->m_obtrusive_locks_granted_waiting_count;
3508 }
3509 mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
3510 }
3511
3512 mdl_request->ticket= ticket;
3513
3514 m_tickets[mdl_request->duration].push_front(ticket);
3515
3516 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
3517
3518 return FALSE;
3519 }
3520
3521
3522 /**
3523 Notify threads holding S/SH metadata locks on an object, which conflict
3524 with a pending X lock.
3525
3526 @note Currently this method is guaranteed to notify shared lock
3527 owners which have MDL_context::m_needs_thr_lock_abort flag
3528 set (as for others conficting locks might have been acquired
3529 on "fast path" and thus might be absent from list of granted
3530 locks).
3531 This is OK as notification for other contexts is anyway
3532 no-op now.
3533
3534 @note We don't notify threads holding other than S/SH types of
3535 conflicting locks on the object since notification should
3536 not be needed and anyway will be no-op for them (unless
3537 they also hold S/SH locks on the object).
3538
3539 @param ctx MDL_context for current thread.
3540 @param lock MDL_lock object representing lock which is to be
3541 acquired.
3542 */
3543
object_lock_notify_conflicting_locks(MDL_context * ctx,MDL_lock * lock)3544 void MDL_lock::object_lock_notify_conflicting_locks(MDL_context *ctx, MDL_lock *lock)
3545 {
3546 Ticket_iterator it(lock->m_granted);
3547 MDL_ticket *conflicting_ticket;
3548
3549 while ((conflicting_ticket= it++))
3550 {
3551 if (conflicting_ticket->get_ctx() != ctx &&
3552 (conflicting_ticket->get_type() == MDL_SHARED ||
3553 conflicting_ticket->get_type() == MDL_SHARED_HIGH_PRIO))
3554 {
3555 MDL_context *conflicting_ctx= conflicting_ticket->get_ctx();
3556
3557 /*
3558 If thread which holds conflicting lock is waiting on table-level
3559 lock or some other non-MDL resource we might need to wake it up
3560 by calling code outside of MDL.
3561
3562 The only scenario in which it is important now looks like:
3563 Thread 1: HANDLER t1 OPEN, acquires S metadata lock on t1.
3564 Thread 2: LOCK TABLES t1 WRITE, t2 READ LOCAL, acquire
3565 SNRW lock on t1, SR lock on t2 and TL_READ THR_LOCK
3566 lock on t2.
3567 Thread 1: Executes UPDATE t2 SET i = 1 or some other DML which
3568 will directly or indirectly block on THR_LOCK for t2.
3569 Thread 2: Does ALTER TABLE t1 ... which tries to upgrade SNRW
3570 metadata lock to X lock and blocks because of S lock
3571 from open HANDLER.
3572
3573 A similar scenario is possible when MERGE tables are used instead
3574 of the READ LOCAL clause.
3575 Once we will get rid of the support for READ LOCAL and MERGE clauses
3576 this code can be removed.
3577 */
3578 ctx->get_owner()->
3579 notify_shared_lock(conflicting_ctx->get_owner(),
3580 conflicting_ctx->get_needs_thr_lock_abort());
3581 }
3582 }
3583 }
3584
3585
3586 /**
3587 Acquire one lock with waiting for conflicting locks to go away if needed.
3588
3589 @param mdl_request [in/out] Lock request object for lock to be acquired
3590
3591 @param lock_wait_timeout [in] Seconds to wait before timeout.
3592
3593 @retval FALSE Success. MDL_request::ticket points to the ticket
3594 for the lock.
3595 @retval TRUE Failure (Out of resources or waiting is aborted),
3596 */
3597
3598 bool
acquire_lock(MDL_request * mdl_request,ulong lock_wait_timeout)3599 MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
3600 {
3601 if (lock_wait_timeout == 0)
3602 {
3603 /*
3604 Resort to try_acquire_lock() in case of zero timeout.
3605
3606 This allows to avoid unnecessary deadlock detection attempt and "fake"
3607 deadlocks which might result from it.
3608 In case of failure to acquire lock, try_acquire_lock() preserves
3609 invariants by updating MDL_lock::fast_path_state and obtrusive locks
3610 count. It also performs SE notification if needed.
3611 */
3612 if (try_acquire_lock(mdl_request))
3613 return true;
3614
3615 if (!mdl_request->ticket)
3616 {
3617 /* We have failed to acquire lock instantly. */
3618 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait");
3619 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
3620 return true;
3621 }
3622 return false;
3623 }
3624
3625 /* Normal, non-zero timeout case. */
3626
3627 MDL_lock *lock;
3628 MDL_ticket *ticket;
3629 struct timespec abs_timeout;
3630 MDL_wait::enum_wait_status wait_status;
3631 /* Do some work outside the critical section. */
3632 set_timespec(&abs_timeout, lock_wait_timeout);
3633
3634 if (try_acquire_lock_impl(mdl_request, &ticket))
3635 return TRUE;
3636
3637 if (mdl_request->ticket)
3638 {
3639 /*
3640 We have managed to acquire lock without waiting.
3641 MDL_lock, MDL_context and MDL_request were updated
3642 accordingly, so we can simply return success.
3643 */
3644 return FALSE;
3645 }
3646
3647 /*
3648 Our attempt to acquire lock without waiting has failed.
3649 As a result of this attempt we got MDL_ticket with m_lock
3650 member pointing to the corresponding MDL_lock object which
3651 has MDL_lock::m_rwlock write-locked.
3652 */
3653 lock= ticket->m_lock;
3654
3655 lock->m_waiting.add_ticket(ticket);
3656
3657 /*
3658 Once we added a pending ticket to the waiting queue,
3659 we must ensure that our wait slot is empty, so
3660 that our lock request can be scheduled. Do that in the
3661 critical section formed by the acquired write lock on MDL_lock.
3662 */
3663 m_wait.reset_status();
3664
3665 if (lock->needs_notification(ticket))
3666 lock->notify_conflicting_locks(this);
3667
3668 mysql_prlock_unlock(&lock->m_rwlock);
3669
3670 #ifdef HAVE_PSI_METADATA_INTERFACE
3671 PSI_metadata_locker_state state;
3672 PSI_metadata_locker *locker= NULL;
3673
3674 if (ticket->m_psi != NULL)
3675 {
3676 locker= PSI_METADATA_CALL(start_metadata_wait)(&state,
3677 ticket->m_psi,
3678 __FILE__, __LINE__);
3679 }
3680 #endif
3681
3682 will_wait_for(ticket);
3683
3684 /* There is a shared or exclusive lock on the object. */
3685 DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait");
3686
3687 find_deadlock();
3688
3689 if (lock->needs_notification(ticket) || lock->needs_connection_check())
3690 {
3691 struct timespec abs_shortwait;
3692 set_timespec(&abs_shortwait, 1);
3693 wait_status= MDL_wait::EMPTY;
3694
3695 while (cmp_timespec(&abs_shortwait, &abs_timeout) <= 0)
3696 {
3697 /* abs_timeout is far away. Wait a short while and notify locks. */
3698 wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE,
3699 mdl_request->key.get_wait_state_name());
3700
3701 if (wait_status != MDL_wait::EMPTY)
3702 break;
3703
3704 if (lock->needs_connection_check() && ! m_owner->is_connected())
3705 {
3706 /*
3707 If this is user-level lock and the client is disconnected don't wait
3708 forever: assume it's the same as statement being killed (this differs
3709 from pre-5.7 where we treat it as timeout, but is more logical).
3710 Using MDL_wait::set_status() to set status atomically wastes one
3711 condition variable wake up but should happen rarely.
3712 We don't want to do this check for all types of metadata locks since
3713 in general case we may want to complete wait/operation even when
3714 connection is lost (e.g. in case of logging into slow/general log).
3715 */
3716 if (! m_wait.set_status(MDL_wait::KILLED))
3717 wait_status= MDL_wait::KILLED;
3718 break;
3719 }
3720
3721 if (lock->needs_notification(ticket))
3722 {
3723 mysql_prlock_wrlock(&lock->m_rwlock);
3724 lock->notify_conflicting_locks(this);
3725 mysql_prlock_unlock(&lock->m_rwlock);
3726 }
3727
3728 set_timespec(&abs_shortwait, 1);
3729 }
3730 if (wait_status == MDL_wait::EMPTY)
3731 wait_status= m_wait.timed_wait(m_owner, &abs_timeout, TRUE,
3732 mdl_request->key.get_wait_state_name());
3733 }
3734 else
3735 {
3736 wait_status= m_wait.timed_wait(m_owner, &abs_timeout, TRUE,
3737 mdl_request->key.get_wait_state_name());
3738 }
3739
3740 done_waiting_for();
3741
3742 #ifdef HAVE_PSI_METADATA_INTERFACE
3743 if (locker != NULL)
3744 {
3745 PSI_METADATA_CALL(end_metadata_wait)(locker, 0);
3746 }
3747 #endif
3748
3749 if (wait_status != MDL_wait::GRANTED)
3750 {
3751 lock->remove_ticket(this, m_pins, &MDL_lock::m_waiting, ticket);
3752
3753 /*
3754 If SEs were notified about impending lock acquisition, the failure
3755 to acquire it requires the same notification as lock release.
3756 */
3757 if (ticket->m_hton_notified)
3758 {
3759 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::POST_RELEASE_NOTIFY);
3760 m_owner->notify_hton_post_release_exclusive(&mdl_request->key);
3761 }
3762
3763 MDL_ticket::destroy(ticket);
3764 switch (wait_status)
3765 {
3766 case MDL_wait::VICTIM:
3767 my_error(ER_LOCK_DEADLOCK, MYF(0));
3768 break;
3769 case MDL_wait::TIMEOUT:
3770 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
3771 break;
3772 case MDL_wait::KILLED:
3773 if (get_owner()->is_killed() == ER_QUERY_TIMEOUT)
3774 my_error(ER_QUERY_TIMEOUT, MYF(0));
3775 else
3776 my_error(ER_QUERY_INTERRUPTED, MYF(0));
3777 break;
3778 default:
3779 assert(0);
3780 break;
3781 }
3782 return TRUE;
3783 }
3784
3785 /*
3786 We have been granted our request.
3787 State of MDL_lock object is already being appropriately updated by a
3788 concurrent thread (@sa MDL_lock:reschedule_waiters()).
3789 So all we need to do is to update MDL_context and MDL_request objects.
3790 */
3791 assert(wait_status == MDL_wait::GRANTED);
3792
3793 m_tickets[mdl_request->duration].push_front(ticket);
3794
3795 mdl_request->ticket= ticket;
3796
3797 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED);
3798
3799 return FALSE;
3800 }
3801
3802
3803 class MDL_request_cmp :
3804 public std::binary_function<const MDL_request*, const MDL_request*, bool>
3805 {
3806 public:
operator ()(const MDL_request * req1,const MDL_request * req2)3807 bool operator()(const MDL_request *req1, const MDL_request *req2)
3808 {
3809 int rc= req1->key.cmp(&req2->key);
3810 /*
3811 In cases when both requests correspond to the same key, we need to put
3812 the request for the stronger lock type first, to avoid extra deadlocks.
3813 We do this by simply comparing types of lock requests.
3814 This works OK since it is mostly needed to avoid the scenario when
3815 LOCK TABLES t1 WRITE, t1 READ acquires SRO lock before SNRW lock.
3816 It won't work in the general case (e.g. SRO is not stronger than SW).
3817 */
3818 if (rc == 0)
3819 rc= static_cast<int>(req2->type) - static_cast<int>(req1->type);
3820 return rc < 0;
3821 }
3822 };
3823
3824
3825
3826 /**
3827 Acquire exclusive locks. There must be no granted locks in the
3828 context.
3829
3830 This is a replacement of lock_table_names(). It is used in
3831 RENAME, DROP and other DDL SQL statements.
3832
3833 @param mdl_requests List of requests for locks to be acquired.
3834
3835 @param lock_wait_timeout Seconds to wait before timeout.
3836
3837 @note The list of requests should not contain non-exclusive lock requests.
3838 There should not be any acquired locks in the context.
3839
3840 @note Assumes that one already owns scoped intention exclusive lock.
3841
3842 @note If acquisition fails any locks with MDL_EXPLICIT duration that had
3843 already been taken, are released. Not just locks with MDL_STATEMENT
3844 and MDL_TRANSACTION duration. This makes acquition of MDL_EXPLICIT
3845 locks atomic (all or nothing). This is needed for the locking
3846 service plugin API.
3847
3848 @retval FALSE Success
3849 @retval TRUE Failure
3850 */
3851
acquire_locks(MDL_request_list * mdl_requests,ulong lock_wait_timeout)3852 bool MDL_context::acquire_locks(MDL_request_list *mdl_requests,
3853 ulong lock_wait_timeout)
3854 {
3855 MDL_request_list::Iterator it(*mdl_requests);
3856 MDL_request **p_req;
3857 MDL_savepoint mdl_svp= mdl_savepoint();
3858 /*
3859 Remember the first MDL_EXPLICIT ticket so that we can release
3860 any new such locks taken if acquisition fails.
3861 */
3862 MDL_ticket *explicit_front= m_tickets[MDL_EXPLICIT].front();
3863 const size_t req_count= mdl_requests->elements();
3864
3865 if (req_count == 0)
3866 return FALSE;
3867
3868 /* Sort requests according to MDL_key. */
3869 Prealloced_array<MDL_request*, 16>
3870 sort_buf(key_memory_MDL_context_acquire_locks);
3871 if (sort_buf.reserve(req_count))
3872 return TRUE;
3873
3874 for (size_t ii=0; ii < req_count; ++ii)
3875 {
3876 sort_buf.push_back(it++);
3877 }
3878
3879 std::sort(sort_buf.begin(), sort_buf.end(), MDL_request_cmp());
3880
3881 size_t num_acquired= 0;
3882 for (p_req= sort_buf.begin(); p_req != sort_buf.end(); p_req++)
3883 {
3884 if (acquire_lock(*p_req, lock_wait_timeout))
3885 goto err;
3886 ++num_acquired;
3887 }
3888 return FALSE;
3889
3890 err:
3891 /*
3892 Release locks we have managed to acquire so far.
3893 Use rollback_to_savepoint() since there may be duplicate
3894 requests that got assigned the same ticket.
3895 */
3896 rollback_to_savepoint(mdl_svp);
3897 /*
3898 Also release the MDL_EXPLICIT locks taken in this call.
3899 The locking service plugin API needs acquisition of such
3900 locks to be atomic as well.
3901 */
3902 release_locks_stored_before(MDL_EXPLICIT, explicit_front);
3903
3904 /* Reset lock requests back to its initial state. */
3905 for (p_req= sort_buf.begin();
3906 p_req != sort_buf.begin() + num_acquired; p_req++)
3907 {
3908 (*p_req)->ticket= NULL;
3909 }
3910 return TRUE;
3911 }
3912
3913
3914 /**
3915 Upgrade a shared metadata lock.
3916
3917 Used in ALTER TABLE and CREATE TABLE.
3918
3919 @param mdl_ticket Lock to upgrade.
3920 @param new_type Lock type to upgrade to.
3921 @param lock_wait_timeout Seconds to wait before timeout.
3922
3923 @note In case of failure to upgrade lock (e.g. because upgrader
3924 was killed) leaves lock in its original state (locked in
3925 shared mode).
3926
3927 @note There can be only one upgrader for a lock or we will have deadlock.
3928 This invariant is ensured by the fact that upgradeable locks SU, SNW
3929 and SNRW are not compatible with each other and themselves in case
3930 of ALTER TABLE operation.
3931 In case of CREATE TABLE operation there is chance of deadlock as 'S'
3932 is compatible with 'S'. But the deadlock is recovered by backoff and
3933 retry mechanism.
3934
3935 @retval FALSE Success
3936 @retval TRUE Failure (thread was killed)
3937 */
3938
3939 bool
upgrade_shared_lock(MDL_ticket * mdl_ticket,enum_mdl_type new_type,ulong lock_wait_timeout)3940 MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket,
3941 enum_mdl_type new_type,
3942 ulong lock_wait_timeout)
3943 {
3944 MDL_request mdl_new_lock_request;
3945 MDL_savepoint mdl_svp= mdl_savepoint();
3946 bool is_new_ticket;
3947 MDL_lock *lock;
3948
3949 DBUG_ENTER("MDL_context::upgrade_shared_lock");
3950 DEBUG_SYNC(get_thd(), "mdl_upgrade_lock");
3951
3952 /*
3953 Do nothing if already upgraded. Used when we FLUSH TABLE under
3954 LOCK TABLES and a table is listed twice in LOCK TABLES list.
3955 */
3956 if (mdl_ticket->has_stronger_or_equal_type(new_type))
3957 DBUG_RETURN(FALSE);
3958
3959 MDL_REQUEST_INIT_BY_KEY(&mdl_new_lock_request,
3960 &mdl_ticket->m_lock->key, new_type,
3961 MDL_TRANSACTION);
3962
3963 if (acquire_lock(&mdl_new_lock_request, lock_wait_timeout))
3964 DBUG_RETURN(TRUE);
3965
3966 is_new_ticket= ! has_lock(mdl_svp, mdl_new_lock_request.ticket);
3967
3968 lock= mdl_ticket->m_lock;
3969
3970 /* Code below assumes that we were upgrading to "obtrusive" type of lock. */
3971 assert(lock->is_obtrusive_lock(new_type));
3972
3973 /* Merge the acquired and the original lock. @todo: move to a method. */
3974 mysql_prlock_wrlock(&lock->m_rwlock);
3975 if (is_new_ticket)
3976 {
3977 lock->m_granted.remove_ticket(mdl_new_lock_request.ticket);
3978 /*
3979 We should not clear HAS_OBTRUSIVE flag in this case as we will
3980 get "obtrusive' lock as result in any case.
3981 */
3982 --lock->m_obtrusive_locks_granted_waiting_count;
3983 }
3984 /*
3985 Set the new type of lock in the ticket. To update state of
3986 MDL_lock object correctly we need to temporarily exclude
3987 ticket from the granted queue or "fast path" counter and
3988 then include lock back into granted queue.
3989 Note that with current code at this point we can't have
3990 "fast path" tickets as upgrade to "obtrusive" locks
3991 materializes tickets normally. Still we cover this case
3992 for completeness.
3993 */
3994 if (mdl_ticket->m_is_fast_path)
3995 {
3996 /*
3997 Decrement of counter in MDL_lock::m_fast_path_state needs to be done
3998 under protection of MDL_lock::m_rwlock to ensure that it is atomic with
3999 changes to MDL_lock::m_granted list and to enforce invariant [INV1].
4000 Note that since we have HAS_OBTRUSIVE flag set at this point all
4001 concurrent lock acquisitions and releases will have to acquire
4002 MDL_lock::m_rwlock, so nobody will see results of this decrement until
4003 m_rwlock is released.
4004 */
4005 lock->fast_path_state_add(
4006 -lock->get_unobtrusive_lock_increment(mdl_ticket->m_type));
4007 mdl_ticket->m_is_fast_path= false;
4008 }
4009 else
4010 {
4011 lock->m_granted.remove_ticket(mdl_ticket);
4012 /*
4013 Also if we are upgrading from "obtrusive" lock we need to temporarily
4014 decrement m_obtrusive_locks_granted_waiting_count counter.
4015 We should not clear HAS_OBTRUSIVE flag in this case as we will get
4016 "obtrusive' lock as result in any case.
4017 */
4018 if (lock->is_obtrusive_lock(mdl_ticket->m_type))
4019 --lock->m_obtrusive_locks_granted_waiting_count;
4020 }
4021
4022 mdl_ticket->m_type= new_type;
4023
4024 lock->m_granted.add_ticket(mdl_ticket);
4025 /*
4026 Since we always upgrade to "obtrusive" type of lock we need to
4027 increment m_obtrusive_locks_granted_waiting_count counter.
4028
4029 HAS_OBTRUSIVE flag has been already set by acquire_lock()
4030 and should not have been cleared since then.
4031 */
4032 assert(lock->m_fast_path_state & MDL_lock::HAS_OBTRUSIVE);
4033 ++lock->m_obtrusive_locks_granted_waiting_count;
4034
4035 mysql_prlock_unlock(&lock->m_rwlock);
4036
4037 /*
4038 The below code can't handle situation when we upgrade to lock requiring
4039 SE notification and it turns out that we already have lock of this type
4040 associated with different ticket.
4041 */
4042 assert(is_new_ticket || ! mdl_new_lock_request.ticket->m_hton_notified);
4043
4044 mdl_ticket->m_hton_notified= mdl_new_lock_request.ticket->m_hton_notified;
4045
4046 if (is_new_ticket)
4047 {
4048 m_tickets[MDL_TRANSACTION].remove(mdl_new_lock_request.ticket);
4049 MDL_ticket::destroy(mdl_new_lock_request.ticket);
4050 }
4051
4052 DBUG_RETURN(FALSE);
4053 }
4054
4055
4056 /**
4057 A fragment of recursive traversal of the wait-for graph
4058 in search for deadlocks. Direct the deadlock visitor to all
4059 contexts that own the lock the current node in the wait-for
4060 graph is waiting for.
4061 As long as the initial node is remembered in the visitor,
4062 a deadlock is found when the same node is seen twice.
4063 */
4064
visit_subgraph(MDL_ticket * waiting_ticket,MDL_wait_for_graph_visitor * gvisitor)4065 bool MDL_lock::visit_subgraph(MDL_ticket *waiting_ticket,
4066 MDL_wait_for_graph_visitor *gvisitor)
4067 {
4068 MDL_ticket *ticket;
4069 MDL_context *src_ctx= waiting_ticket->get_ctx();
4070 bool result= TRUE;
4071
4072 mysql_prlock_rdlock(&m_rwlock);
4073
4074 /*
4075 Iterators must be initialized after taking a read lock.
4076
4077 Note that MDL_ticket's which correspond to lock requests satisfied
4078 on "fast path" are not present in m_granted list and thus
4079 corresponding edges are missing from wait-for graph.
4080 It is OK since contexts with "fast path" tickets are not allowed to
4081 wait for any resource (they have to convert "fast path" tickets to
4082 normal tickets first) and thus cannot participate in deadlock.
4083 @sa MDL_contex::will_wait_for().
4084 */
4085 Ticket_iterator granted_it(m_granted);
4086 Ticket_iterator waiting_it(m_waiting);
4087
4088 /*
4089 MDL_lock's waiting and granted queues and MDL_context::m_waiting_for
4090 member are updated by different threads when the lock is granted
4091 (see MDL_context::acquire_lock() and MDL_lock::reschedule_waiters()).
4092 As a result, here we may encounter a situation when MDL_lock data
4093 already reflects the fact that the lock was granted but
4094 m_waiting_for member has not been updated yet.
4095
4096 For example, imagine that:
4097
4098 thread1: Owns SNW lock on table t1.
4099 thread2: Attempts to acquire SW lock on t1,
4100 but sees an active SNW lock.
4101 Thus adds the ticket to the waiting queue and
4102 sets m_waiting_for to point to the ticket.
4103 thread1: Releases SNW lock, updates MDL_lock object to
4104 grant SW lock to thread2 (moves the ticket for
4105 SW from waiting to the active queue).
4106 Attempts to acquire a new SNW lock on t1,
4107 sees an active SW lock (since it is present in the
4108 active queue), adds ticket for SNW lock to the waiting
4109 queue, sets m_waiting_for to point to this ticket.
4110
4111 At this point deadlock detection algorithm run by thread1 will see that:
4112 - Thread1 waits for SNW lock on t1 (since m_waiting_for is set).
4113 - SNW lock is not granted, because it conflicts with active SW lock
4114 owned by thread 2 (since ticket for SW is present in granted queue).
4115 - Thread2 waits for SW lock (since its m_waiting_for has not been
4116 updated yet!).
4117 - SW lock is not granted because there is pending SNW lock from thread1.
4118 Therefore deadlock should exist [sic!].
4119
4120 To avoid detection of such false deadlocks we need to check the "actual"
4121 status of the ticket being waited for, before analyzing its blockers.
4122 We do this by checking the wait status of the context which is waiting
4123 for it. To avoid races this has to be done under protection of
4124 MDL_lock::m_rwlock lock.
4125 */
4126 if (src_ctx->m_wait.get_status() != MDL_wait::EMPTY)
4127 {
4128 result= FALSE;
4129 goto end;
4130 }
4131
4132 /*
4133 To avoid visiting nodes which were already marked as victims of
4134 deadlock detection (or whose requests were already satisfied) we
4135 enter the node only after peeking at its wait status.
4136 This is necessary to avoid active waiting in a situation
4137 when previous searches for a deadlock already selected the
4138 node we're about to enter as a victim (see the comment
4139 in MDL_context::find_deadlock() for explanation why several searches
4140 can be performed for the same wait).
4141 There is no guarantee that the node isn't chosen a victim while we
4142 are visiting it but this is OK: in the worst case we might do some
4143 extra work and one more context might be chosen as a victim.
4144 */
4145 if (gvisitor->enter_node(src_ctx))
4146 goto end;
4147
4148 /*
4149 We do a breadth-first search first -- that is, inspect all
4150 edges of the current node, and only then follow up to the next
4151 node. In workloads that involve wait-for graph loops this
4152 has proven to be a more efficient strategy [citation missing].
4153 */
4154 while ((ticket= granted_it++))
4155 {
4156 /* Filter out edges that point to the same node. */
4157 if (ticket->get_ctx() != src_ctx &&
4158 ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
4159 gvisitor->inspect_edge(ticket->get_ctx()))
4160 {
4161 goto end_leave_node;
4162 }
4163 }
4164
4165 while ((ticket= waiting_it++))
4166 {
4167 /* Filter out edges that point to the same node. */
4168 if (ticket->get_ctx() != src_ctx &&
4169 ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
4170 gvisitor->inspect_edge(ticket->get_ctx()))
4171 {
4172 goto end_leave_node;
4173 }
4174 }
4175
4176 /* Recurse and inspect all adjacent nodes. */
4177 granted_it.rewind();
4178 while ((ticket= granted_it++))
4179 {
4180 if (ticket->get_ctx() != src_ctx &&
4181 ticket->is_incompatible_when_granted(waiting_ticket->get_type()) &&
4182 ticket->get_ctx()->visit_subgraph(gvisitor))
4183 {
4184 goto end_leave_node;
4185 }
4186 }
4187
4188 waiting_it.rewind();
4189 while ((ticket= waiting_it++))
4190 {
4191 if (ticket->get_ctx() != src_ctx &&
4192 ticket->is_incompatible_when_waiting(waiting_ticket->get_type()) &&
4193 ticket->get_ctx()->visit_subgraph(gvisitor))
4194 {
4195 goto end_leave_node;
4196 }
4197 }
4198
4199 result= FALSE;
4200
4201 end_leave_node:
4202 gvisitor->leave_node(src_ctx);
4203
4204 end:
4205 mysql_prlock_unlock(&m_rwlock);
4206 return result;
4207 }
4208
4209
4210 /**
4211 Traverse a portion of wait-for graph which is reachable
4212 through the edge represented by this ticket and search
4213 for deadlocks.
4214
4215 @retval TRUE A deadlock is found. A pointer to deadlock
4216 victim is saved in the visitor.
4217 @retval FALSE
4218 */
4219
accept_visitor(MDL_wait_for_graph_visitor * gvisitor)4220 bool MDL_ticket::accept_visitor(MDL_wait_for_graph_visitor *gvisitor)
4221 {
4222 return m_lock->visit_subgraph(this, gvisitor);
4223 }
4224
4225
4226 /**
4227 A fragment of recursive traversal of the wait-for graph of
4228 MDL contexts in the server in search for deadlocks.
4229 Assume this MDL context is a node in the wait-for graph,
4230 and direct the visitor to all adjacent nodes. As long
4231 as the starting node is remembered in the visitor, a
4232 deadlock is found when the same node is visited twice.
4233 One MDL context is connected to another in the wait-for
4234 graph if it waits on a resource that is held by the other
4235 context.
4236
4237 @retval TRUE A deadlock is found. A pointer to deadlock
4238 victim is saved in the visitor.
4239 @retval FALSE
4240 */
4241
visit_subgraph(MDL_wait_for_graph_visitor * gvisitor)4242 bool MDL_context::visit_subgraph(MDL_wait_for_graph_visitor *gvisitor)
4243 {
4244 bool result= FALSE;
4245
4246 mysql_prlock_rdlock(&m_LOCK_waiting_for);
4247
4248 if (m_waiting_for)
4249 result= m_waiting_for->accept_visitor(gvisitor);
4250
4251 mysql_prlock_unlock(&m_LOCK_waiting_for);
4252
4253 return result;
4254 }
4255
4256
4257 /**
4258 Try to find a deadlock. This function produces no errors.
4259
4260 @note If during deadlock resolution context which performs deadlock
4261 detection is chosen as a victim it will be informed about the
4262 fact by setting VICTIM status to its wait slot.
4263 */
4264
find_deadlock()4265 void MDL_context::find_deadlock()
4266 {
4267 while (1)
4268 {
4269 /*
4270 The fact that we use fresh instance of gvisitor for each
4271 search performed by find_deadlock() below is important,
4272 the code responsible for victim selection relies on this.
4273 */
4274 Deadlock_detection_visitor dvisitor(this);
4275 MDL_context *victim;
4276
4277 if (! visit_subgraph(&dvisitor))
4278 {
4279 /* No deadlocks are found! */
4280 break;
4281 }
4282
4283 victim= dvisitor.get_victim();
4284
4285 /*
4286 Failure to change status of the victim is OK as it means
4287 that the victim has received some other message and is
4288 about to stop its waiting/to break deadlock loop.
4289 Even when the initiator of the deadlock search is
4290 chosen the victim, we need to set the respective wait
4291 result in order to "close" it for any attempt to
4292 schedule the request.
4293 This is needed to avoid a possible race during
4294 cleanup in case when the lock request on which the
4295 context was waiting is concurrently satisfied.
4296 */
4297 (void) victim->m_wait.set_status(MDL_wait::VICTIM);
4298 victim->unlock_deadlock_victim();
4299
4300 if (victim == this)
4301 break;
4302 /*
4303 After adding a new edge to the waiting graph we found that it
4304 creates a loop (i.e. there is a deadlock). We decided to destroy
4305 this loop by removing an edge, but not the one that we added.
4306 Since this doesn't guarantee that all loops created by addition
4307 of the new edge are destroyed, we have to repeat the search.
4308 */
4309 }
4310 }
4311
4312
4313 /**
4314 Release lock.
4315
4316 @param duration Lock duration.
4317 @param ticket Ticket for lock to be released.
4318
4319 */
4320
release_lock(enum_mdl_duration duration,MDL_ticket * ticket)4321 void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket)
4322 {
4323 MDL_lock *lock= ticket->m_lock;
4324 MDL_key key_for_hton;
4325 DBUG_ENTER("MDL_context::release_lock");
4326 DBUG_PRINT("enter", ("db=%s name=%s", lock->key.db_name(),
4327 lock->key.name()));
4328
4329 assert(this == ticket->get_ctx());
4330 mysql_mutex_assert_not_owner(&LOCK_open);
4331
4332
4333 /*
4334 If lock we are about to release requires post-release notification
4335 of SEs, we need to save its MDL_key on stack. This is necessary to
4336 be able to pass this key to SEs after corresponding MDL_lock object
4337 might be freed as result of lock release.
4338 */
4339 if (ticket->m_hton_notified)
4340 key_for_hton.mdl_key_init(&lock->key);
4341
4342 if (ticket->m_is_fast_path)
4343 {
4344 /*
4345 We are releasing ticket which represents lock request which was
4346 satisfied using "fast path". We can use "fast path" release
4347 algorithm of release for it as well.
4348 */
4349 MDL_lock::fast_path_state_t unobtrusive_lock_increment=
4350 lock->get_unobtrusive_lock_increment(ticket->get_type());
4351 bool is_singleton= mdl_locks.is_lock_object_singleton(&lock->key);
4352
4353 /* We should not have "fast path" tickets for "obtrusive" lock types. */
4354 assert(unobtrusive_lock_increment != 0);
4355
4356 /*
4357 We need decrement part of m_fast_path_state which holds number of
4358 acquired "fast path" locks of this type. This needs to be done
4359 by atomic compare-and-swap.
4360
4361 The same atomic compare-and-swap needs to check:
4362
4363 *) If HAS_OBSTRUSIVE flag is set. In this case we need to acquire
4364 MDL_lock::m_rwlock before changing m_fast_path_state. This is
4365 needed to enforce invariant [INV1] and also because we might
4366 have to atomically wake-up some waiters for our "unobtrusive"
4367 lock to go away.
4368 *) If we are about to release last "fast path" lock and there
4369 are no "slow path" locks. In this case we need to count
4370 MDL_lock object as unused and maybe even delete some
4371 unused MDL_lock objects eventually.
4372
4373 Similarly to the case with "fast path" acquisition it is OK to
4374 perform ordinary read of MDL_lock::m_fast_path_state as correctness
4375 of value returned by it will be validated by atomic compare-and-swap.
4376 Again, in theory, this algorithm will work correctly if the read will
4377 return random values.
4378 */
4379 MDL_lock::fast_path_state_t old_state= lock->m_fast_path_state;
4380 bool last_use;
4381
4382 do
4383 {
4384 if (old_state & MDL_lock::HAS_OBTRUSIVE)
4385 {
4386 mysql_prlock_wrlock(&lock->m_rwlock);
4387 /*
4388 It is possible that obtrusive lock has gone away since we have
4389 read m_fast_path_state value. This means that there is possibility
4390 that there are no "slow path" locks (HAS_SLOW_PATH is not set) and
4391 we are about to release last "fast path" lock. In this case MDL_lock
4392 will become unused and needs to be counted as such eventually.
4393 */
4394 last_use= (lock->fast_path_state_add(-unobtrusive_lock_increment) ==
4395 unobtrusive_lock_increment);
4396 /*
4397 There might be some lock requests waiting for ticket being released
4398 to go away. Since this is "fast path" ticket it represents
4399 "unobtrusive" type of lock. In this case if there are any waiters
4400 for it there should be "obtrusive" type of request among them.
4401 */
4402 if (lock->m_obtrusive_locks_granted_waiting_count)
4403 lock->reschedule_waiters();
4404 mysql_prlock_unlock(&lock->m_rwlock);
4405 goto end_fast_path;
4406 }
4407 /*
4408 If there are no "slow path" locks (HAS_SLOW_PATH is not set) and
4409 we are about to release last "fast path" lock - MDL_lock object
4410 will become unused and needs to be counted as such.
4411 */
4412 last_use= (old_state == unobtrusive_lock_increment);
4413 }
4414 while (! lock->fast_path_state_cas(&old_state,
4415 old_state - unobtrusive_lock_increment));
4416
4417 end_fast_path:
4418 /* Don't count singleton MDL_lock objects as unused. */
4419 if (last_use && ! is_singleton)
4420 mdl_locks.lock_object_unused(this, m_pins);
4421 }
4422 else
4423 {
4424 /*
4425 Lock request represented by ticket was acquired using "slow path"
4426 or ticket was materialized later. We need to use "slow path" release.
4427 */
4428 lock->remove_ticket(this, m_pins, &MDL_lock::m_granted, ticket);
4429 }
4430
4431 m_tickets[duration].remove(ticket);
4432
4433 if (ticket->m_hton_notified)
4434 {
4435 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::POST_RELEASE_NOTIFY);
4436 m_owner->notify_hton_post_release_exclusive(&key_for_hton);
4437 }
4438
4439 MDL_ticket::destroy(ticket);
4440
4441 DBUG_VOID_RETURN;
4442 }
4443
4444
4445 /**
4446 Release lock with explicit duration.
4447
4448 @param ticket Ticket for lock to be released.
4449
4450 */
4451
release_lock(MDL_ticket * ticket)4452 void MDL_context::release_lock(MDL_ticket *ticket)
4453 {
4454 assert(ticket->m_duration == MDL_EXPLICIT);
4455
4456 release_lock(MDL_EXPLICIT, ticket);
4457 }
4458
4459
4460 /**
4461 Release all locks associated with the context. If the sentinel
4462 is not NULL, do not release locks stored in the list after and
4463 including the sentinel.
4464
4465 Statement and transactional locks are added to the beginning of
4466 the corresponding lists, i.e. stored in reverse temporal order.
4467 This allows to employ this function to:
4468 - back off in case of a lock conflict.
4469 - release all locks in the end of a statement or transaction
4470 - rollback to a savepoint.
4471 */
4472
release_locks_stored_before(enum_mdl_duration duration,MDL_ticket * sentinel)4473 void MDL_context::release_locks_stored_before(enum_mdl_duration duration,
4474 MDL_ticket *sentinel)
4475 {
4476 MDL_ticket *ticket;
4477 Ticket_iterator it(m_tickets[duration]);
4478 DBUG_ENTER("MDL_context::release_locks_stored_before");
4479
4480 if (m_tickets[duration].is_empty())
4481 DBUG_VOID_RETURN;
4482
4483 while ((ticket= it++) && ticket != sentinel)
4484 {
4485 DBUG_PRINT("info", ("found lock to release ticket=%p", ticket));
4486 release_lock(duration, ticket);
4487 }
4488
4489 DBUG_VOID_RETURN;
4490 }
4491
4492
4493 /**
4494 Release all explicit locks in the context which correspond to the
4495 same name/object as this lock request.
4496
4497 @param name One of the locks for the name/object for which all
4498 locks should be released.
4499 */
4500
release_all_locks_for_name(MDL_ticket * name)4501 void MDL_context::release_all_locks_for_name(MDL_ticket *name)
4502 {
4503 /* Use MDL_ticket::m_lock to identify other locks for the same object. */
4504 MDL_lock *lock= name->m_lock;
4505
4506 /* Remove matching lock tickets from the context. */
4507 MDL_ticket *ticket;
4508 Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
4509
4510 while ((ticket= it_ticket++))
4511 {
4512 assert(ticket->m_lock);
4513 if (ticket->m_lock == lock)
4514 release_lock(MDL_EXPLICIT, ticket);
4515 }
4516 }
4517
4518
4519 /**
4520 Release all explicit locks in the context for which the release()
4521 method of the provided visitor evalates to true.
4522
4523 @param visitor Object to ask if the lock should be released.
4524 */
4525
release_locks(MDL_release_locks_visitor * visitor)4526 void MDL_context::release_locks(MDL_release_locks_visitor *visitor)
4527 {
4528 /* Remove matching lock tickets from the context. */
4529 MDL_ticket *ticket;
4530 Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
4531
4532 while ((ticket= it_ticket++))
4533 {
4534 assert(ticket->m_lock);
4535 if (visitor->release(ticket))
4536 release_lock(MDL_EXPLICIT, ticket);
4537 }
4538 }
4539
4540
4541 /**
4542 Downgrade an EXCLUSIVE or SHARED_NO_WRITE lock to shared metadata lock.
4543
4544 @param type Type of lock to which exclusive lock should be downgraded.
4545 */
4546
downgrade_lock(enum_mdl_type new_type)4547 void MDL_ticket::downgrade_lock(enum_mdl_type new_type)
4548 {
4549 bool new_type_is_unobtrusive;
4550 mysql_mutex_assert_not_owner(&LOCK_open);
4551
4552 /*
4553 Do nothing if already downgraded. Used when we FLUSH TABLE under
4554 LOCK TABLES and a table is listed twice in LOCK TABLES list.
4555 Note that this code might even try to "downgrade" a weak lock
4556 (e.g. SW) to a stronger one (e.g SNRW). So we can't even assert
4557 here that target lock is weaker than existing lock.
4558 */
4559 if (m_type == new_type || !has_stronger_or_equal_type(new_type))
4560 return;
4561
4562 /* Only allow downgrade from EXCLUSIVE and SHARED_NO_WRITE. */
4563 assert(m_type == MDL_EXCLUSIVE ||
4564 m_type == MDL_SHARED_NO_WRITE);
4565
4566 /* Below we assume that we always downgrade "obtrusive" locks. */
4567 assert(m_lock->is_obtrusive_lock(m_type));
4568
4569 new_type_is_unobtrusive= ! m_lock->is_obtrusive_lock(new_type);
4570
4571 mysql_prlock_wrlock(&m_lock->m_rwlock);
4572 /*
4573 To update state of MDL_lock object correctly we need to temporarily
4574 exclude ticket from the granted queue and then include it back.
4575
4576 Since we downgrade only "obtrusive" locks we can always assume that the
4577 ticket for the lock being downgraded is a "slow path" ticket.
4578 If we are downgrading to non-"obtrusive" lock we also should decrement
4579 counter of waiting and granted "obtrusive" locks.
4580 */
4581 m_lock->m_granted.remove_ticket(this);
4582 if (new_type_is_unobtrusive)
4583 {
4584 if ((--m_lock->m_obtrusive_locks_granted_waiting_count) == 0)
4585 {
4586 /*
4587 We are downgrading the last "obtrusive" lock. So we need to clear
4588 HAS_OBTRUSIVE flag.
4589 Note that it doesn't matter that we do this before including ticket
4590 to MDL_lock::m_granted list. Threads requesting "obtrusive" locks
4591 won't see this until MDL_lock::m_rwlock is released. And threads
4592 requesting "unobtrusive" locks don't care about this ticket.
4593 */
4594 MDL_lock::fast_path_state_t old_state= m_lock->m_fast_path_state;
4595 while (! m_lock->fast_path_state_cas(&old_state,
4596 old_state & ~MDL_lock::HAS_OBTRUSIVE))
4597 { }
4598 }
4599 }
4600 m_type= new_type;
4601 m_lock->m_granted.add_ticket(this);
4602 m_lock->reschedule_waiters();
4603 mysql_prlock_unlock(&m_lock->m_rwlock);
4604
4605 /*
4606 When we downgrade X lock for which SEs were notified about lock
4607 acquisition we treat situation in the same way as lock release
4608 (from SEs notification point of view).
4609 */
4610 if (m_hton_notified)
4611 {
4612 mysql_mdl_set_status(m_psi, MDL_ticket::POST_RELEASE_NOTIFY);
4613 m_ctx->get_owner()->notify_hton_post_release_exclusive(&m_lock->key);
4614 m_hton_notified= false;
4615 mysql_mdl_set_status(m_psi, MDL_ticket::GRANTED);
4616 }
4617 }
4618
4619
4620 /**
4621 Auxiliary function which allows to check if we have some kind of lock on
4622 a object. Returns TRUE if we have a lock of an equal to given or stronger
4623 type.
4624
4625 @param mdl_namespace Id of object namespace
4626 @param db Name of the database
4627 @param name Name of the object
4628 @param mdl_type Lock type. Pass in the weakest type to find
4629 out if there is at least some lock.
4630
4631 @return TRUE if current context contains satisfied lock for the object,
4632 FALSE otherwise.
4633 */
4634
4635 bool
owns_equal_or_stronger_lock(MDL_key::enum_mdl_namespace mdl_namespace,const char * db,const char * name,enum_mdl_type mdl_type)4636 MDL_context::owns_equal_or_stronger_lock(
4637 MDL_key::enum_mdl_namespace mdl_namespace,
4638 const char *db, const char *name,
4639 enum_mdl_type mdl_type)
4640 {
4641 MDL_request mdl_request;
4642 enum_mdl_duration not_unused;
4643 /* We don't care about exact duration of lock here. */
4644 MDL_REQUEST_INIT(&mdl_request,
4645 mdl_namespace, db, name, mdl_type, MDL_TRANSACTION);
4646 MDL_ticket *ticket= find_ticket(&mdl_request, ¬_unused);
4647
4648 assert(ticket == NULL || ticket->m_lock);
4649
4650 return ticket;
4651 }
4652
4653
4654 /**
4655 Find the first context which owns the lock and inspect it by
4656 calling MDL_context_visitor::visit_context() method.
4657
4658 @return True in case error (e.g. OOM). False otherwise. There
4659 is no guarantee that owner was found in either case.
4660 @note This method only works properly for locks which were
4661 acquired using "slow" path.
4662 */
4663
find_lock_owner(const MDL_key * mdl_key,MDL_context_visitor * visitor)4664 bool MDL_context::find_lock_owner(const MDL_key *mdl_key,
4665 MDL_context_visitor *visitor)
4666 {
4667 MDL_lock *lock;
4668 MDL_context *owner;
4669 bool pinned;
4670
4671 if (fix_pins())
4672 return true;
4673
4674 retry:
4675 if ((lock= mdl_locks.find(m_pins, mdl_key, &pinned)) == MY_ERRPTR)
4676 return true;
4677
4678 /* No MDL_lock object, no owner, nothing to visit. */
4679 if (lock == NULL)
4680 return false;
4681
4682 mysql_prlock_rdlock(&lock->m_rwlock);
4683
4684 if (lock->m_fast_path_state & MDL_lock::IS_DESTROYED)
4685 {
4686 mysql_prlock_unlock(&lock->m_rwlock);
4687 if (pinned)
4688 lf_hash_search_unpin(m_pins);
4689 DEBUG_SYNC(get_thd(), "mdl_find_lock_owner_is_destroyed");
4690 goto retry;
4691 }
4692
4693 if (pinned)
4694 lf_hash_search_unpin(m_pins);
4695
4696 if ((owner= lock->get_lock_owner()))
4697 visitor->visit_context(owner);
4698
4699 mysql_prlock_unlock(&lock->m_rwlock);
4700
4701 return false;
4702 }
4703
4704
4705 /**
4706 Check if we have any pending locks which conflict with existing shared lock.
4707
4708 @pre The ticket must match an acquired lock.
4709
4710 @return TRUE if there is a conflicting lock request, FALSE otherwise.
4711 */
4712
has_pending_conflicting_lock() const4713 bool MDL_ticket::has_pending_conflicting_lock() const
4714 {
4715 return m_lock->has_pending_conflicting_lock(m_type);
4716 }
4717
4718 /** Return a key identifying this lock. */
4719
get_key() const4720 const MDL_key *MDL_ticket::get_key() const
4721 {
4722 return &m_lock->key;
4723 }
4724
4725 /**
4726 Releases metadata locks that were acquired after a specific savepoint.
4727
4728 @note Used to release tickets acquired during a savepoint unit.
4729 @note It's safe to iterate and unlock any locks after taken after this
4730 savepoint because other statements that take other special locks
4731 cause a implicit commit (ie LOCK TABLES).
4732 */
4733
rollback_to_savepoint(const MDL_savepoint & mdl_savepoint)4734 void MDL_context::rollback_to_savepoint(const MDL_savepoint &mdl_savepoint)
4735 {
4736 DBUG_ENTER("MDL_context::rollback_to_savepoint");
4737
4738 /* If savepoint is NULL, it is from the start of the transaction. */
4739 release_locks_stored_before(MDL_STATEMENT, mdl_savepoint.m_stmt_ticket);
4740 release_locks_stored_before(MDL_TRANSACTION, mdl_savepoint.m_trans_ticket);
4741
4742 DBUG_VOID_RETURN;
4743 }
4744
4745
4746 /**
4747 Release locks acquired by normal statements (SELECT, UPDATE,
4748 DELETE, etc) in the course of a transaction. Do not release
4749 HANDLER locks, if there are any.
4750
4751 This method is used at the end of a transaction, in
4752 implementation of COMMIT (implicit or explicit) and ROLLBACK.
4753 */
4754
release_transactional_locks()4755 void MDL_context::release_transactional_locks()
4756 {
4757 DBUG_ENTER("MDL_context::release_transactional_locks");
4758 release_locks_stored_before(MDL_STATEMENT, NULL);
4759 release_locks_stored_before(MDL_TRANSACTION, NULL);
4760 DBUG_VOID_RETURN;
4761 }
4762
4763
release_statement_locks()4764 void MDL_context::release_statement_locks()
4765 {
4766 DBUG_ENTER("MDL_context::release_transactional_locks");
4767 release_locks_stored_before(MDL_STATEMENT, NULL);
4768 DBUG_VOID_RETURN;
4769 }
4770
4771
4772 /**
4773 Does this savepoint have this lock?
4774
4775 @retval TRUE The ticket is older than the savepoint or
4776 is an LT, HA or GLR ticket. Thus it belongs
4777 to the savepoint or has explicit duration.
4778 @retval FALSE The ticket is newer than the savepoint.
4779 and is not an LT, HA or GLR ticket.
4780 */
4781
has_lock(const MDL_savepoint & mdl_savepoint,MDL_ticket * mdl_ticket)4782 bool MDL_context::has_lock(const MDL_savepoint &mdl_savepoint,
4783 MDL_ticket *mdl_ticket)
4784 {
4785 MDL_ticket *ticket;
4786 /* Start from the beginning, most likely mdl_ticket's been just acquired. */
4787 MDL_context::Ticket_iterator s_it(m_tickets[MDL_STATEMENT]);
4788 MDL_context::Ticket_iterator t_it(m_tickets[MDL_TRANSACTION]);
4789
4790 while ((ticket= s_it++) && ticket != mdl_savepoint.m_stmt_ticket)
4791 {
4792 if (ticket == mdl_ticket)
4793 return FALSE;
4794 }
4795
4796 while ((ticket= t_it++) && ticket != mdl_savepoint.m_trans_ticket)
4797 {
4798 if (ticket == mdl_ticket)
4799 return FALSE;
4800 }
4801 return TRUE;
4802 }
4803
4804
4805 /**
4806 Does this context have an lock of the given namespace?
4807
4808 @retval true At least one lock of given namespace held
4809 @retval false No locks of the given namespace held
4810 */
4811
has_locks(MDL_key::enum_mdl_namespace mdl_namespace) const4812 bool MDL_context::has_locks(MDL_key::enum_mdl_namespace mdl_namespace) const
4813 {
4814 MDL_ticket *ticket;
4815
4816 for (int i=0; i < MDL_DURATION_END; i++)
4817 {
4818 enum_mdl_duration duration= static_cast<enum_mdl_duration>(i);
4819
4820 Ticket_iterator it(m_tickets[duration]);
4821 while ((ticket= it++))
4822 {
4823 if (ticket->get_key()->mdl_namespace() == mdl_namespace)
4824 return true;
4825 }
4826 }
4827 return false;
4828 }
4829
4830
4831 /**
4832 Do we hold any locks which are possibly being waited
4833 for by another MDL_context?
4834
4835 @retval TRUE A lock being 'waited_for' was found.
4836 @retval FALSE No one waits for the lock(s) we hold.
4837
4838 @note Should only be called from the thread which
4839 owns the MDL_context
4840 */
4841
has_locks_waited_for() const4842 bool MDL_context::has_locks_waited_for() const
4843 {
4844 MDL_ticket *ticket;
4845
4846 for (int i=0; i < MDL_DURATION_END; i++)
4847 {
4848 const enum_mdl_duration duration= static_cast<enum_mdl_duration>(i);
4849 Ticket_iterator it(m_tickets[duration]);
4850 while ((ticket= it++))
4851 {
4852 MDL_lock *const lock= ticket->m_lock;
4853
4854 mysql_prlock_rdlock(&lock->m_rwlock);
4855 const bool has_waiters= !lock->m_waiting.is_empty();
4856 mysql_prlock_unlock(&lock->m_rwlock);
4857
4858 if (!has_waiters)
4859 return true;
4860 }
4861 }
4862 return false;
4863 }
4864
4865
4866
4867 /**
4868 Change lock duration for transactional lock.
4869
4870 @param ticket Ticket representing lock.
4871 @param duration Lock duration to be set.
4872
4873 @note This method only supports changing duration of
4874 transactional lock to some other duration.
4875 */
4876
set_lock_duration(MDL_ticket * mdl_ticket,enum_mdl_duration duration)4877 void MDL_context::set_lock_duration(MDL_ticket *mdl_ticket,
4878 enum_mdl_duration duration)
4879 {
4880 assert(mdl_ticket->m_duration == MDL_TRANSACTION &&
4881 duration != MDL_TRANSACTION);
4882
4883 m_tickets[MDL_TRANSACTION].remove(mdl_ticket);
4884 m_tickets[duration].push_front(mdl_ticket);
4885 #ifndef NDEBUG
4886 mdl_ticket->m_duration= duration;
4887 #endif
4888 }
4889
4890
4891 /**
4892 Set explicit duration for all locks in the context.
4893 */
4894
set_explicit_duration_for_all_locks()4895 void MDL_context::set_explicit_duration_for_all_locks()
4896 {
4897 int i;
4898 MDL_ticket *ticket;
4899
4900 /*
4901 In the most common case when this function is called list
4902 of transactional locks is bigger than list of locks with
4903 explicit duration. So we start by swapping these two lists
4904 and then move elements from new list of transactional
4905 locks and list of statement locks to list of locks with
4906 explicit duration.
4907 */
4908
4909 m_tickets[MDL_EXPLICIT].swap(m_tickets[MDL_TRANSACTION]);
4910
4911 for (i= 0; i < MDL_EXPLICIT; i++)
4912 {
4913 Ticket_iterator it_ticket(m_tickets[i]);
4914
4915 while ((ticket= it_ticket++))
4916 {
4917 m_tickets[i].remove(ticket);
4918 m_tickets[MDL_EXPLICIT].push_front(ticket);
4919 }
4920 }
4921
4922 #ifndef NDEBUG
4923 Ticket_iterator exp_it(m_tickets[MDL_EXPLICIT]);
4924
4925 while ((ticket= exp_it++))
4926 ticket->m_duration= MDL_EXPLICIT;
4927 #endif
4928 }
4929
4930
4931 /**
4932 Set transactional duration for all locks in the context.
4933 */
4934
set_transaction_duration_for_all_locks()4935 void MDL_context::set_transaction_duration_for_all_locks()
4936 {
4937 MDL_ticket *ticket;
4938
4939 /*
4940 In the most common case when this function is called list
4941 of explicit locks is bigger than two other lists (in fact,
4942 list of statement locks is always empty). So we start by
4943 swapping list of explicit and transactional locks and then
4944 move contents of new list of explicit locks to list of
4945 locks with transactional duration.
4946 */
4947
4948 assert(m_tickets[MDL_STATEMENT].is_empty());
4949
4950 m_tickets[MDL_TRANSACTION].swap(m_tickets[MDL_EXPLICIT]);
4951
4952 Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
4953
4954 while ((ticket= it_ticket++))
4955 {
4956 m_tickets[MDL_EXPLICIT].remove(ticket);
4957 m_tickets[MDL_TRANSACTION].push_front(ticket);
4958 }
4959
4960 #ifndef NDEBUG
4961 Ticket_iterator trans_it(m_tickets[MDL_TRANSACTION]);
4962
4963 while ((ticket= trans_it++))
4964 ticket->m_duration= MDL_TRANSACTION;
4965 #endif
4966 }
4967