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