MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mdl.h
1 #ifndef MDL_H
2 #define MDL_H
3 /* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software Foundation,
16  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
17 
18 #if defined(__IBMC__) || defined(__IBMCPP__)
19 /* Further down, "next_in_lock" and "next_in_context" have the same type,
20  and in "sql_plist.h" this leads to an identical signature, which causes
21  problems in function overloading.
22 */
23 #pragma namemangling(v5)
24 #endif
25 
26 
27 #include "sql_plist.h"
28 #include <my_sys.h>
29 #include <m_string.h>
30 #include <mysql_com.h>
31 
32 #include <algorithm>
33 
34 class THD;
35 
36 class MDL_context;
37 class MDL_lock;
38 class MDL_ticket;
39 
49 #define ENTER_COND(C, M, S, O) enter_cond(C, M, S, O, __func__, __FILE__, __LINE__)
50 
56 #define EXIT_COND(S) exit_cond(S, __func__, __FILE__, __LINE__)
57 
64 {
65 public:
66  virtual ~MDL_context_owner() {}
67 
83  virtual void enter_cond(mysql_cond_t *cond, mysql_mutex_t *mutex,
84  const PSI_stage_info *stage, PSI_stage_info *old_stage,
85  const char *src_function, const char *src_file,
86  int src_line) = 0;
87 
98  virtual void exit_cond(const PSI_stage_info *stage,
99  const char *src_function, const char *src_file,
100  int src_line) = 0;
104  virtual int is_killed() = 0;
105 
110  virtual THD* get_thd() = 0;
111 
115  virtual bool notify_shared_lock(MDL_context_owner *in_use,
116  bool needs_thr_lock_abort) = 0;
117 };
118 
126 enum enum_mdl_type {
127  /*
128  An intention exclusive metadata lock. Used only for scoped locks.
129  Owner of this type of lock can acquire upgradable exclusive locks on
130  individual objects.
131  Compatible with other IX locks, but is incompatible with scoped S and
132  X locks.
133  */
134  MDL_INTENTION_EXCLUSIVE= 0,
135  /*
136  A shared metadata lock.
137  To be used in cases when we are interested in object metadata only
138  and there is no intention to access object data (e.g. for stored
139  routines or during preparing prepared statements).
140  We also mis-use this type of lock for open HANDLERs, since lock
141  acquired by this statement has to be compatible with lock acquired
142  by LOCK TABLES ... WRITE statement, i.e. SNRW (We can't get by by
143  acquiring S lock at HANDLER ... OPEN time and upgrading it to SR
144  lock for HANDLER ... READ as it doesn't solve problem with need
145  to abort DML statements which wait on table level lock while having
146  open HANDLER in the same connection).
147  To avoid deadlock which may occur when SNRW lock is being upgraded to
148  X lock for table on which there is an active S lock which is owned by
149  thread which waits in its turn for table-level lock owned by thread
150  performing upgrade we have to use thr_abort_locks_for_thread()
151  facility in such situation.
152  This problem does not arise for locks on stored routines as we don't
153  use SNRW locks for them. It also does not arise when S locks are used
154  during PREPARE calls as table-level locks are not acquired in this
155  case.
156  */
157  MDL_SHARED,
158  /*
159  A high priority shared metadata lock.
160  Used for cases when there is no intention to access object data (i.e.
161  data in the table).
162  "High priority" means that, unlike other shared locks, it is granted
163  ignoring pending requests for exclusive locks. Intended for use in
164  cases when we only need to access metadata and not data, e.g. when
165  filling an INFORMATION_SCHEMA table.
166  Since SH lock is compatible with SNRW lock, the connection that
167  holds SH lock lock should not try to acquire any kind of table-level
168  or row-level lock, as this can lead to a deadlock. Moreover, after
169  acquiring SH lock, the connection should not wait for any other
170  resource, as it might cause starvation for X locks and a potential
171  deadlock during upgrade of SNW or SNRW to X lock (e.g. if the
172  upgrading connection holds the resource that is being waited for).
173  */
174  MDL_SHARED_HIGH_PRIO,
175  /*
176  A shared metadata lock for cases when there is an intention to read data
177  from table.
178  A connection holding this kind of lock can read table metadata and read
179  table data (after acquiring appropriate table and row-level locks).
180  This means that one can only acquire TL_READ, TL_READ_NO_INSERT, and
181  similar table-level locks on table if one holds SR MDL lock on it.
182  To be used for tables in SELECTs, subqueries, and LOCK TABLE ... READ
183  statements.
184  */
185  MDL_SHARED_READ,
186  /*
187  A shared metadata lock for cases when there is an intention to modify
188  (and not just read) data in the table.
189  A connection holding SW lock can read table metadata and modify or read
190  table data (after acquiring appropriate table and row-level locks).
191  To be used for tables to be modified by INSERT, UPDATE, DELETE
192  statements, but not LOCK TABLE ... WRITE or DDL). Also taken by
193  SELECT ... FOR UPDATE.
194  */
195  MDL_SHARED_WRITE,
196  /*
197  An upgradable shared metadata lock for cases when there is an intention
198  to modify (and not just read) data in the table.
199  Can be upgraded to MDL_SHARED_NO_WRITE and MDL_EXCLUSIVE.
200  A connection holding SU lock can read table metadata and modify or read
201  table data (after acquiring appropriate table and row-level locks).
202  To be used for the first phase of ALTER TABLE.
203  */
204  MDL_SHARED_UPGRADABLE,
205  /*
206  An upgradable shared metadata lock which blocks all attempts to update
207  table data, allowing reads.
208  A connection holding this kind of lock can read table metadata and read
209  table data.
210  Can be upgraded to X metadata lock.
211  Note, that since this type of lock is not compatible with SNRW or SW
212  lock types, acquiring appropriate engine-level locks for reading
213  (TL_READ* for MyISAM, shared row locks in InnoDB) should be
214  contention-free.
215  To be used for the first phase of ALTER TABLE, when copying data between
216  tables, to allow concurrent SELECTs from the table, but not UPDATEs.
217  */
218  MDL_SHARED_NO_WRITE,
219  /*
220  An upgradable shared metadata lock which allows other connections
221  to access table metadata, but not data.
222  It blocks all attempts to read or update table data, while allowing
223  INFORMATION_SCHEMA and SHOW queries.
224  A connection holding this kind of lock can read table metadata modify and
225  read table data.
226  Can be upgraded to X metadata lock.
227  To be used for LOCK TABLES WRITE statement.
228  Not compatible with any other lock type except S and SH.
229  */
230  MDL_SHARED_NO_READ_WRITE,
231  /*
232  An exclusive metadata lock.
233  A connection holding this lock can modify both table's metadata and data.
234  No other type of metadata lock can be granted while this lock is held.
235  To be used for CREATE/DROP/RENAME TABLE statements and for execution of
236  certain phases of other DDL statements.
237  */
238  MDL_EXCLUSIVE,
239  /* This should be the last !!! */
240  MDL_TYPE_END};
241 
242 
245 enum enum_mdl_duration {
250  MDL_STATEMENT= 0,
255  MDL_TRANSACTION,
260  MDL_EXPLICIT,
261  /* This should be the last ! */
262  MDL_DURATION_END };
263 
264 
266 #define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1)
267 
268 
278 class MDL_key
279 {
280 public:
281 #ifdef HAVE_PSI_INTERFACE
282  static void init_psi_keys();
283 #endif
284 
300  enum enum_mdl_namespace { GLOBAL=0,
301  SCHEMA,
302  TABLE,
303  FUNCTION,
304  PROCEDURE,
305  TRIGGER,
306  EVENT,
307  COMMIT,
308  /* This should be the last ! */
309  NAMESPACE_END };
310 
311  const uchar *ptr() const { return (uchar*) m_ptr; }
312  uint length() const { return m_length; }
313 
314  const char *db_name() const { return m_ptr + 1; }
315  uint db_name_length() const { return m_db_name_length; }
316 
317  const char *name() const { return m_ptr + m_db_name_length + 2; }
318  uint name_length() const { return m_length - m_db_name_length - 3; }
319 
320  enum_mdl_namespace mdl_namespace() const
321  { return (enum_mdl_namespace)(m_ptr[0]); }
322 
334  void mdl_key_init(enum_mdl_namespace mdl_namespace,
335  const char *db, const char *name)
336  {
337  m_ptr[0]= (char) mdl_namespace;
338  /*
339  It is responsibility of caller to ensure that db and object names
340  are not longer than NAME_LEN. Still we play safe and try to avoid
341  buffer overruns.
342  */
343  DBUG_ASSERT(strlen(db) <= NAME_LEN && strlen(name) <= NAME_LEN);
344  m_db_name_length= static_cast<uint16>(strmake(m_ptr + 1, db, NAME_LEN) -
345  m_ptr - 1);
346  m_length= static_cast<uint16>(strmake(m_ptr + m_db_name_length + 2, name,
347  NAME_LEN) - m_ptr + 1);
348  }
349  void mdl_key_init(const MDL_key *rhs)
350  {
351  memcpy(m_ptr, rhs->m_ptr, rhs->m_length);
352  m_length= rhs->m_length;
353  m_db_name_length= rhs->m_db_name_length;
354  }
355  bool is_equal(const MDL_key *rhs) const
356  {
357  return (m_length == rhs->m_length &&
358  memcmp(m_ptr, rhs->m_ptr, m_length) == 0);
359  }
363  int cmp(const MDL_key *rhs) const
364  {
365  /*
366  The key buffer is always '\0'-terminated. Since key
367  character set is utf-8, we can safely assume that no
368  character starts with a zero byte.
369  */
370  using std::min;
371  return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length));
372  }
373 
374  MDL_key(const MDL_key *rhs)
375  {
376  mdl_key_init(rhs);
377  }
378  MDL_key(enum_mdl_namespace namespace_arg,
379  const char *db_arg, const char *name_arg)
380  {
381  mdl_key_init(namespace_arg, db_arg, name_arg);
382  }
383  MDL_key() {} /* To use when part of MDL_request. */
384 
390  {
391  return & m_namespace_to_wait_state_name[(int)mdl_namespace()];
392  }
393 
394 private:
395  uint16 m_length;
396  uint16 m_db_name_length;
397  char m_ptr[MAX_MDLKEY_LENGTH];
398  static PSI_stage_info m_namespace_to_wait_state_name[NAMESPACE_END];
399 private:
400  MDL_key(const MDL_key &); /* not implemented */
401  MDL_key &operator=(const MDL_key &); /* not implemented */
402 };
403 
404 
419 {
420 public:
422  enum enum_mdl_type type;
424  enum enum_mdl_duration duration;
425 
430  MDL_request **prev_in_list;
436 
439 
440 public:
441  static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
442  { return alloc_root(mem_root, size); }
443  static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
444 
445  void init(MDL_key::enum_mdl_namespace namespace_arg,
446  const char *db_arg, const char *name_arg,
447  enum_mdl_type mdl_type_arg,
448  enum_mdl_duration mdl_duration_arg);
449  void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg,
450  enum_mdl_duration mdl_duration_arg);
452  inline void set_type(enum_mdl_type type_arg)
453  {
454  DBUG_ASSERT(ticket == NULL);
455  type= type_arg;
456  }
457 
458  /*
459  This is to work around the ugliness of TABLE_LIST
460  compiler-generated assignment operator. It is currently used
461  in several places to quickly copy "most" of the members of the
462  table list. These places currently never assume that the mdl
463  request is carried over to the new TABLE_LIST, or shared
464  between lists.
465 
466  This method does not initialize the instance being assigned!
467  Use of init() for initialization after this assignment operator
468  is mandatory. Can only be used before the request has been
469  granted.
470  */
471  MDL_request& operator=(const MDL_request &rhs)
472  {
473  ticket= NULL;
474  /* Do nothing, in particular, don't try to copy the key. */
475  return *this;
476  }
477  /* Another piece of ugliness for TABLE_LIST constructor */
478  MDL_request() {}
479 
480  MDL_request(const MDL_request *rhs)
481  :type(rhs->type),
482  duration(rhs->duration),
483  ticket(NULL),
484  key(&rhs->key)
485  {}
486 };
487 
488 
489 typedef void (*mdl_cached_object_release_hook)(void *);
490 
491 
498 {
499 public:
500  virtual bool enter_node(MDL_context *node) = 0;
501  virtual void leave_node(MDL_context *node) = 0;
502 
503  virtual bool inspect_edge(MDL_context *dest) = 0;
504  virtual ~MDL_wait_for_graph_visitor();
506 public:
516 };
517 
524 {
525 public:
526  virtual ~MDL_wait_for_subgraph();
527 
532  virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0;
533 
534  enum enum_deadlock_weight
535  {
536  DEADLOCK_WEIGHT_DML= 0,
537  DEADLOCK_WEIGHT_DDL= 100
538  };
539  /* A helper used to determine which lock request should be aborted. */
540  virtual uint get_deadlock_weight() const = 0;
541 };
542 
543 
565 {
566 public:
572  MDL_ticket **prev_in_context;
578  MDL_ticket **prev_in_lock;
579 public:
580  bool has_pending_conflicting_lock() const;
581 
582  MDL_context *get_ctx() const { return m_ctx; }
583  bool is_upgradable_or_exclusive() const
584  {
585  return m_type == MDL_SHARED_UPGRADABLE ||
586  m_type == MDL_SHARED_NO_WRITE ||
587  m_type == MDL_SHARED_NO_READ_WRITE ||
588  m_type == MDL_EXCLUSIVE;
589  }
590  enum_mdl_type get_type() const { return m_type; }
591  MDL_lock *get_lock() const { return m_lock; }
592  void downgrade_lock(enum_mdl_type type);
593 
594  bool has_stronger_or_equal_type(enum_mdl_type type) const;
595 
596  bool is_incompatible_when_granted(enum_mdl_type type) const;
597  bool is_incompatible_when_waiting(enum_mdl_type type) const;
598 
600  virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor);
601  virtual uint get_deadlock_weight() const;
602 private:
603  friend class MDL_context;
604 
605  MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg
606 #ifndef DBUG_OFF
607  , enum_mdl_duration duration_arg
608 #endif
609  )
610  : m_type(type_arg),
611 #ifndef DBUG_OFF
612  m_duration(duration_arg),
613 #endif
614  m_ctx(ctx_arg),
615  m_lock(NULL)
616  {}
617 
618  static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg
619 #ifndef DBUG_OFF
620  , enum_mdl_duration duration_arg
621 #endif
622  );
623  static void destroy(MDL_ticket *ticket);
624 private:
626  enum enum_mdl_type m_type;
627 #ifndef DBUG_OFF
628 
632  enum_mdl_duration m_duration;
633 #endif
634 
637  MDL_context *m_ctx;
638 
642  MDL_lock *m_lock;
643 
644 private:
645  MDL_ticket(const MDL_ticket &); /* not implemented */
646  MDL_ticket &operator=(const MDL_ticket &); /* not implemented */
647 };
648 
649 
658 {
659 public:
660  MDL_savepoint() {};
661 
662 private:
663  MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket)
664  : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket)
665  {}
666 
667  friend class MDL_context;
668 
669 private:
674  MDL_ticket *m_stmt_ticket;
679  MDL_ticket *m_trans_ticket;
680 };
681 
682 
687 class MDL_wait
688 {
689 public:
690  MDL_wait();
691  ~MDL_wait();
692 
693  enum enum_wait_status { EMPTY = 0, GRANTED, VICTIM, TIMEOUT, KILLED };
694 
695  bool set_status(enum_wait_status result_arg);
696  enum_wait_status get_status();
697  void reset_status();
698  enum_wait_status timed_wait(MDL_context_owner *owner,
699  struct timespec *abs_timeout,
700  bool signal_timeout,
701  const PSI_stage_info *wait_state_name);
702 private:
710  mysql_mutex_t m_LOCK_wait_status;
711  mysql_cond_t m_COND_wait_status;
712  enum_wait_status m_wait_status;
713 };
714 
715 
716 typedef I_P_List<MDL_request, I_P_List_adapter<MDL_request,
718  &MDL_request::prev_in_list>,
721 
728 {
729 public:
730  typedef I_P_List<MDL_ticket,
733  &MDL_ticket::prev_in_context> >
734  Ticket_list;
735 
737 
738  MDL_context();
739  void destroy();
740 
741  bool try_acquire_lock(MDL_request *mdl_request);
742  bool acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout);
743  bool acquire_locks(MDL_request_list *requests, ulong lock_wait_timeout);
744  bool upgrade_shared_lock(MDL_ticket *mdl_ticket,
745  enum_mdl_type new_type,
746  ulong lock_wait_timeout);
747 
748  bool clone_ticket(MDL_request *mdl_request);
749 
751  void release_lock(MDL_ticket *ticket);
752 
753  bool is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
754  const char *db, const char *name,
755  enum_mdl_type mdl_type);
756 
757  bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket);
758 
759  inline bool has_locks() const
760  {
761  return !(m_tickets[MDL_STATEMENT].is_empty() &&
762  m_tickets[MDL_TRANSACTION].is_empty() &&
763  m_tickets[MDL_EXPLICIT].is_empty());
764  }
765 
766  MDL_savepoint mdl_savepoint()
767  {
768  return MDL_savepoint(m_tickets[MDL_STATEMENT].front(),
769  m_tickets[MDL_TRANSACTION].front());
770  }
771 
774  void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration);
775 
776  void release_statement_locks();
778  void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
779 
780  MDL_context_owner *get_owner() { return m_owner; }
781 
783  inline uint get_deadlock_weight() const
784  { return m_waiting_for->get_deadlock_weight(); }
793  void init(MDL_context_owner *arg) { m_owner= arg; }
794 
795  void set_needs_thr_lock_abort(bool needs_thr_lock_abort)
796  {
797  /*
798  @note In theory, this member should be modified under protection
799  of some lock since it can be accessed from different threads.
800  In practice, this is not necessary as code which reads this
801  value and so might miss the fact that value was changed will
802  always re-try reading it after small timeout and therefore
803  will see the new value eventually.
804  */
805  m_needs_thr_lock_abort= needs_thr_lock_abort;
806  }
807  bool get_needs_thr_lock_abort() const
808  {
809  return m_needs_thr_lock_abort;
810  }
811 public:
817 private:
872  Ticket_list m_tickets[MDL_DURATION_END];
873  MDL_context_owner *m_owner;
883  bool m_needs_thr_lock_abort;
884 
892  mysql_prlock_t m_LOCK_waiting_for;
900  MDL_wait_for_subgraph *m_waiting_for;
901 private:
902  THD *get_thd() const { return m_owner->get_thd(); }
903  MDL_ticket *find_ticket(MDL_request *mdl_req,
904  enum_mdl_duration *duration);
905  void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel);
906  void release_lock(enum_mdl_duration duration, MDL_ticket *ticket);
907  bool try_acquire_lock_impl(MDL_request *mdl_request,
908  MDL_ticket **out_ticket);
909 
910 public:
911  void find_deadlock();
912 
914 
916  void will_wait_for(MDL_wait_for_subgraph *waiting_for_arg)
917  {
918  mysql_prlock_wrlock(&m_LOCK_waiting_for);
919  m_waiting_for= waiting_for_arg;
920  mysql_prlock_unlock(&m_LOCK_waiting_for);
921  }
922 
925  {
926  mysql_prlock_wrlock(&m_LOCK_waiting_for);
927  m_waiting_for= NULL;
928  mysql_prlock_unlock(&m_LOCK_waiting_for);
929  }
930  void lock_deadlock_victim()
931  {
932  mysql_prlock_rdlock(&m_LOCK_waiting_for);
933  }
934  void unlock_deadlock_victim()
935  {
936  mysql_prlock_unlock(&m_LOCK_waiting_for);
937  }
938 private:
939  MDL_context(const MDL_context &rhs); /* not implemented */
940  MDL_context &operator=(MDL_context &rhs); /* not implemented */
941 };
942 
943 
944 void mdl_init();
945 void mdl_destroy();
946 
947 
948 #ifndef DBUG_OFF
949 extern mysql_mutex_t LOCK_open;
950 #endif
951 
952 
953 /*
954  Start-up parameter for the maximum size of the unused MDL_lock objects cache
955  and a constant for its default value.
956 */
957 extern ulong mdl_locks_cache_size;
958 static const ulong MDL_LOCKS_CACHE_SIZE_DEFAULT = 1024;
959 
960 /*
961  Start-up parameter for the number of partitions of the hash
962  containing all the MDL_lock objects and a constant for
963  its default value.
964 */
965 extern ulong mdl_locks_hash_partitions;
966 static const ulong MDL_LOCKS_HASH_PARTITIONS_DEFAULT = 8;
967 
968 /*
969  Metadata locking subsystem tries not to grant more than
970  max_write_lock_count high-prio, strong locks successively,
971  to avoid starving out weak, low-prio locks.
972 */
973 extern "C" ulong max_write_lock_count;
974 #endif