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 | #include "sql_plist.h" |
19 | #include <my_sys.h> |
20 | #include <m_string.h> |
21 | #include <mysql_com.h> |
22 | #include <lf.h> |
23 | |
24 | class THD; |
25 | |
26 | class MDL_context; |
27 | class MDL_lock; |
28 | class MDL_ticket; |
29 | bool ok_for_lower_case_names(const char *name); |
30 | |
31 | /** |
32 | @def ENTER_COND(C, M, S, O) |
33 | Start a wait on a condition. |
34 | @param C the condition to wait on |
35 | @param M the associated mutex |
36 | @param S the new stage to enter |
37 | @param O the previous stage |
38 | @sa EXIT_COND(). |
39 | */ |
40 | #define ENTER_COND(C, M, S, O) enter_cond(C, M, S, O, __func__, __FILE__, __LINE__) |
41 | |
42 | /** |
43 | @def EXIT_COND(S) |
44 | End a wait on a condition |
45 | @param S the new stage to enter |
46 | */ |
47 | #define EXIT_COND(S) exit_cond(S, __func__, __FILE__, __LINE__) |
48 | |
49 | /** |
50 | An interface to separate the MDL module from the THD, and the rest of the |
51 | server code. |
52 | */ |
53 | |
54 | class MDL_context_owner |
55 | { |
56 | public: |
57 | virtual ~MDL_context_owner() {} |
58 | |
59 | /** |
60 | Enter a condition wait. |
61 | For @c enter_cond() / @c exit_cond() to work the mutex must be held before |
62 | @c enter_cond(); this mutex is then released by @c exit_cond(). |
63 | Usage must be: lock mutex; enter_cond(); your code; exit_cond(). |
64 | @param cond the condition to wait on |
65 | @param mutex the associated mutex |
66 | @param [in] stage the stage to enter, or NULL |
67 | @param [out] old_stage the previous stage, or NULL |
68 | @param src_function function name of the caller |
69 | @param src_file file name of the caller |
70 | @param src_line line number of the caller |
71 | @sa ENTER_COND(), THD::enter_cond() |
72 | @sa EXIT_COND(), THD::exit_cond() |
73 | */ |
74 | virtual void enter_cond(mysql_cond_t *cond, mysql_mutex_t *mutex, |
75 | const PSI_stage_info *stage, PSI_stage_info *old_stage, |
76 | const char *src_function, const char *src_file, |
77 | int src_line) = 0; |
78 | |
79 | /** |
80 | @def EXIT_COND(S) |
81 | End a wait on a condition |
82 | @param [in] stage the new stage to enter |
83 | @param src_function function name of the caller |
84 | @param src_file file name of the caller |
85 | @param src_line line number of the caller |
86 | @sa ENTER_COND(), THD::enter_cond() |
87 | @sa EXIT_COND(), THD::exit_cond() |
88 | */ |
89 | virtual void exit_cond(const PSI_stage_info *stage, |
90 | const char *src_function, const char *src_file, |
91 | int src_line) = 0; |
92 | /** |
93 | Has the owner thread been killed? |
94 | */ |
95 | virtual int is_killed() = 0; |
96 | |
97 | /** |
98 | This one is only used for DEBUG_SYNC. |
99 | (Do not use it to peek/poke into other parts of THD.) |
100 | */ |
101 | virtual THD* get_thd() = 0; |
102 | |
103 | /** |
104 | @see THD::notify_shared_lock() |
105 | */ |
106 | virtual bool notify_shared_lock(MDL_context_owner *in_use, |
107 | bool needs_thr_lock_abort) = 0; |
108 | }; |
109 | |
110 | /** |
111 | Type of metadata lock request. |
112 | |
113 | @sa Comments for MDL_object_lock::can_grant_lock() and |
114 | MDL_scoped_lock::can_grant_lock() for details. |
115 | */ |
116 | |
117 | enum enum_mdl_type { |
118 | /* |
119 | An intention exclusive metadata lock. Used only for scoped locks. |
120 | Owner of this type of lock can acquire upgradable exclusive locks on |
121 | individual objects. |
122 | Compatible with other IX locks, but is incompatible with scoped S and |
123 | X locks. |
124 | */ |
125 | MDL_INTENTION_EXCLUSIVE= 0, |
126 | /* |
127 | A shared metadata lock. |
128 | To be used in cases when we are interested in object metadata only |
129 | and there is no intention to access object data (e.g. for stored |
130 | routines or during preparing prepared statements). |
131 | We also mis-use this type of lock for open HANDLERs, since lock |
132 | acquired by this statement has to be compatible with lock acquired |
133 | by LOCK TABLES ... WRITE statement, i.e. SNRW (We can't get by by |
134 | acquiring S lock at HANDLER ... OPEN time and upgrading it to SR |
135 | lock for HANDLER ... READ as it doesn't solve problem with need |
136 | to abort DML statements which wait on table level lock while having |
137 | open HANDLER in the same connection). |
138 | To avoid deadlock which may occur when SNRW lock is being upgraded to |
139 | X lock for table on which there is an active S lock which is owned by |
140 | thread which waits in its turn for table-level lock owned by thread |
141 | performing upgrade we have to use thr_abort_locks_for_thread() |
142 | facility in such situation. |
143 | This problem does not arise for locks on stored routines as we don't |
144 | use SNRW locks for them. It also does not arise when S locks are used |
145 | during PREPARE calls as table-level locks are not acquired in this |
146 | case. |
147 | */ |
148 | MDL_SHARED, |
149 | /* |
150 | A high priority shared metadata lock. |
151 | Used for cases when there is no intention to access object data (i.e. |
152 | data in the table). |
153 | "High priority" means that, unlike other shared locks, it is granted |
154 | ignoring pending requests for exclusive locks. Intended for use in |
155 | cases when we only need to access metadata and not data, e.g. when |
156 | filling an INFORMATION_SCHEMA table. |
157 | Since SH lock is compatible with SNRW lock, the connection that |
158 | holds SH lock lock should not try to acquire any kind of table-level |
159 | or row-level lock, as this can lead to a deadlock. Moreover, after |
160 | acquiring SH lock, the connection should not wait for any other |
161 | resource, as it might cause starvation for X locks and a potential |
162 | deadlock during upgrade of SNW or SNRW to X lock (e.g. if the |
163 | upgrading connection holds the resource that is being waited for). |
164 | */ |
165 | MDL_SHARED_HIGH_PRIO, |
166 | /* |
167 | A shared metadata lock for cases when there is an intention to read data |
168 | from table. |
169 | A connection holding this kind of lock can read table metadata and read |
170 | table data (after acquiring appropriate table and row-level locks). |
171 | This means that one can only acquire TL_READ, TL_READ_NO_INSERT, and |
172 | similar table-level locks on table if one holds SR MDL lock on it. |
173 | To be used for tables in SELECTs, subqueries, and LOCK TABLE ... READ |
174 | statements. |
175 | */ |
176 | MDL_SHARED_READ, |
177 | /* |
178 | A shared metadata lock for cases when there is an intention to modify |
179 | (and not just read) data in the table. |
180 | A connection holding SW lock can read table metadata and modify or read |
181 | table data (after acquiring appropriate table and row-level locks). |
182 | To be used for tables to be modified by INSERT, UPDATE, DELETE |
183 | statements, but not LOCK TABLE ... WRITE or DDL). Also taken by |
184 | SELECT ... FOR UPDATE. |
185 | */ |
186 | MDL_SHARED_WRITE, |
187 | /* |
188 | An upgradable shared metadata lock for cases when there is an intention |
189 | to modify (and not just read) data in the table. |
190 | Can be upgraded to MDL_SHARED_NO_WRITE and MDL_EXCLUSIVE. |
191 | A connection holding SU lock can read table metadata and modify or read |
192 | table data (after acquiring appropriate table and row-level locks). |
193 | To be used for the first phase of ALTER TABLE. |
194 | */ |
195 | MDL_SHARED_UPGRADABLE, |
196 | /* |
197 | A shared metadata lock for cases when we need to read data from table |
198 | and block all concurrent modifications to it (for both data and metadata). |
199 | Used by LOCK TABLES READ statement. |
200 | */ |
201 | MDL_SHARED_READ_ONLY, |
202 | /* |
203 | An upgradable shared metadata lock which blocks all attempts to update |
204 | table data, allowing reads. |
205 | A connection holding this kind of lock can read table metadata and read |
206 | table data. |
207 | Can be upgraded to X metadata lock. |
208 | Note, that since this type of lock is not compatible with SNRW or SW |
209 | lock types, acquiring appropriate engine-level locks for reading |
210 | (TL_READ* for MyISAM, shared row locks in InnoDB) should be |
211 | contention-free. |
212 | To be used for the first phase of ALTER TABLE, when copying data between |
213 | tables, to allow concurrent SELECTs from the table, but not UPDATEs. |
214 | */ |
215 | MDL_SHARED_NO_WRITE, |
216 | /* |
217 | An upgradable shared metadata lock which allows other connections |
218 | to access table metadata, but not data. |
219 | It blocks all attempts to read or update table data, while allowing |
220 | INFORMATION_SCHEMA and SHOW queries. |
221 | A connection holding this kind of lock can read table metadata modify and |
222 | read table data. |
223 | Can be upgraded to X metadata lock. |
224 | To be used for LOCK TABLES WRITE statement. |
225 | Not compatible with any other lock type except S and SH. |
226 | */ |
227 | MDL_SHARED_NO_READ_WRITE, |
228 | /* |
229 | An exclusive metadata lock. |
230 | A connection holding this lock can modify both table's metadata and data. |
231 | No other type of metadata lock can be granted while this lock is held. |
232 | To be used for CREATE/DROP/RENAME TABLE statements and for execution of |
233 | certain phases of other DDL statements. |
234 | */ |
235 | MDL_EXCLUSIVE, |
236 | /* This should be the last !!! */ |
237 | MDL_TYPE_END}; |
238 | |
239 | |
240 | /** Duration of metadata lock. */ |
241 | |
242 | enum enum_mdl_duration { |
243 | /** |
244 | Locks with statement duration are automatically released at the end |
245 | of statement or transaction. |
246 | */ |
247 | MDL_STATEMENT= 0, |
248 | /** |
249 | Locks with transaction duration are automatically released at the end |
250 | of transaction. |
251 | */ |
252 | MDL_TRANSACTION, |
253 | /** |
254 | Locks with explicit duration survive the end of statement and transaction. |
255 | They have to be released explicitly by calling MDL_context::release_lock(). |
256 | */ |
257 | MDL_EXPLICIT, |
258 | /* This should be the last ! */ |
259 | MDL_DURATION_END }; |
260 | |
261 | |
262 | /** Maximal length of key for metadata locking subsystem. */ |
263 | #define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1) |
264 | |
265 | |
266 | /** |
267 | Metadata lock object key. |
268 | |
269 | A lock is requested or granted based on a fully qualified name and type. |
270 | E.g. They key for a table consists of <0 (=table)>+<database>+<table name>. |
271 | Elsewhere in the comments this triple will be referred to simply as "key" |
272 | or "name". |
273 | */ |
274 | |
275 | class MDL_key |
276 | { |
277 | public: |
278 | #ifdef HAVE_PSI_INTERFACE |
279 | static void init_psi_keys(); |
280 | #endif |
281 | |
282 | /** |
283 | Object namespaces. |
284 | Sic: when adding a new member to this enum make sure to |
285 | update m_namespace_to_wait_state_name array in mdl.cc! |
286 | |
287 | Different types of objects exist in different namespaces |
288 | - TABLE is for tables and views. |
289 | - FUNCTION is for stored functions. |
290 | - PROCEDURE is for stored procedures. |
291 | - TRIGGER is for triggers. |
292 | - EVENT is for event scheduler events |
293 | Note that although there isn't metadata locking on triggers, |
294 | it's necessary to have a separate namespace for them since |
295 | MDL_key is also used outside of the MDL subsystem. |
296 | */ |
297 | enum enum_mdl_namespace { GLOBAL=0, |
298 | SCHEMA, |
299 | TABLE, |
300 | FUNCTION, |
301 | PROCEDURE, |
302 | PACKAGE_BODY, |
303 | TRIGGER, |
304 | EVENT, |
305 | COMMIT, |
306 | USER_LOCK, /* user level locks. */ |
307 | /* This should be the last ! */ |
308 | NAMESPACE_END }; |
309 | |
310 | const uchar *ptr() const { return (uchar*) m_ptr; } |
311 | uint length() const { return m_length; } |
312 | |
313 | const char *db_name() const { return m_ptr + 1; } |
314 | uint db_name_length() const { return m_db_name_length; } |
315 | |
316 | const char *name() const { return m_ptr + m_db_name_length + 2; } |
317 | uint name_length() const { return m_length - m_db_name_length - 3; } |
318 | |
319 | enum_mdl_namespace mdl_namespace() const |
320 | { return (enum_mdl_namespace)(m_ptr[0]); } |
321 | |
322 | /** |
323 | Construct a metadata lock key from a triplet (mdl_namespace, |
324 | database and name). |
325 | |
326 | @remark The key for a table is <mdl_namespace>+<database name>+<table name> |
327 | |
328 | @param mdl_namespace Id of namespace of object to be locked |
329 | @param db Name of database to which the object belongs |
330 | @param name Name of of the object |
331 | @param key Where to store the the MDL key. |
332 | */ |
333 | void mdl_key_init(enum_mdl_namespace mdl_namespace_arg, |
334 | const char *db, const char *name_arg) |
335 | { |
336 | m_ptr[0]= (char) mdl_namespace_arg; |
337 | /* |
338 | It is responsibility of caller to ensure that db and object names |
339 | are not longer than NAME_LEN. Still we play safe and try to avoid |
340 | buffer overruns. |
341 | */ |
342 | DBUG_ASSERT(strlen(db) <= NAME_LEN); |
343 | DBUG_ASSERT(strlen(name_arg) <= 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, |
347 | name_arg, |
348 | NAME_LEN) - m_ptr + 1); |
349 | m_hash_value= my_hash_sort(&my_charset_bin, (uchar*) m_ptr + 1, |
350 | m_length - 1); |
351 | DBUG_SLOW_ASSERT(mdl_namespace_arg == USER_LOCK || ok_for_lower_case_names(db)); |
352 | } |
353 | void mdl_key_init(const MDL_key *rhs) |
354 | { |
355 | memcpy(m_ptr, rhs->m_ptr, rhs->m_length); |
356 | m_length= rhs->m_length; |
357 | m_db_name_length= rhs->m_db_name_length; |
358 | m_hash_value= rhs->m_hash_value; |
359 | } |
360 | bool is_equal(const MDL_key *rhs) const |
361 | { |
362 | return (m_length == rhs->m_length && |
363 | memcmp(m_ptr, rhs->m_ptr, m_length) == 0); |
364 | } |
365 | /** |
366 | Compare two MDL keys lexicographically. |
367 | */ |
368 | int cmp(const MDL_key *rhs) const |
369 | { |
370 | /* |
371 | The key buffer is always '\0'-terminated. Since key |
372 | character set is utf-8, we can safely assume that no |
373 | character starts with a zero byte. |
374 | */ |
375 | return memcmp(m_ptr, rhs->m_ptr, MY_MIN(m_length, rhs->m_length)); |
376 | } |
377 | |
378 | MDL_key(const MDL_key *rhs) |
379 | { |
380 | mdl_key_init(rhs); |
381 | } |
382 | MDL_key(enum_mdl_namespace namespace_arg, |
383 | const char *db_arg, const char *name_arg) |
384 | { |
385 | mdl_key_init(namespace_arg, db_arg, name_arg); |
386 | } |
387 | MDL_key() {} /* To use when part of MDL_request. */ |
388 | |
389 | /** |
390 | Get thread state name to be used in case when we have to |
391 | wait on resource identified by key. |
392 | */ |
393 | const PSI_stage_info * get_wait_state_name() const |
394 | { |
395 | return & m_namespace_to_wait_state_name[(int)mdl_namespace()]; |
396 | } |
397 | my_hash_value_type hash_value() const |
398 | { |
399 | return m_hash_value + mdl_namespace(); |
400 | } |
401 | my_hash_value_type tc_hash_value() const |
402 | { |
403 | return m_hash_value; |
404 | } |
405 | |
406 | private: |
407 | uint16 m_length; |
408 | uint16 m_db_name_length; |
409 | my_hash_value_type m_hash_value; |
410 | char m_ptr[MAX_MDLKEY_LENGTH]; |
411 | static PSI_stage_info m_namespace_to_wait_state_name[NAMESPACE_END]; |
412 | private: |
413 | MDL_key(const MDL_key &); /* not implemented */ |
414 | MDL_key &operator=(const MDL_key &); /* not implemented */ |
415 | friend my_hash_value_type mdl_hash_function(CHARSET_INFO *, |
416 | const uchar *, size_t); |
417 | }; |
418 | |
419 | |
420 | /** |
421 | A pending metadata lock request. |
422 | |
423 | A lock request and a granted metadata lock are represented by |
424 | different classes because they have different allocation |
425 | sites and hence different lifetimes. The allocation of lock requests is |
426 | controlled from outside of the MDL subsystem, while allocation of granted |
427 | locks (tickets) is controlled within the MDL subsystem. |
428 | |
429 | MDL_request is a C structure, you don't need to call a constructor |
430 | or destructor for it. |
431 | */ |
432 | |
433 | class MDL_request |
434 | { |
435 | public: |
436 | /** Type of metadata lock. */ |
437 | enum enum_mdl_type type; |
438 | /** Duration for requested lock. */ |
439 | enum enum_mdl_duration duration; |
440 | |
441 | /** |
442 | Pointers for participating in the list of lock requests for this context. |
443 | */ |
444 | MDL_request *next_in_list; |
445 | MDL_request **prev_in_list; |
446 | /** |
447 | Pointer to the lock ticket object for this lock request. |
448 | Valid only if this lock request is satisfied. |
449 | */ |
450 | MDL_ticket *ticket; |
451 | |
452 | /** A lock is requested based on a fully qualified name and type. */ |
453 | MDL_key key; |
454 | |
455 | public: |
456 | |
457 | static void *operator new(size_t size, MEM_ROOT *mem_root) throw () |
458 | { return alloc_root(mem_root, size); } |
459 | static void operator delete(void *, MEM_ROOT *) {} |
460 | |
461 | void init(MDL_key::enum_mdl_namespace namespace_arg, |
462 | const char *db_arg, const char *name_arg, |
463 | enum_mdl_type mdl_type_arg, |
464 | enum_mdl_duration mdl_duration_arg); |
465 | void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg, |
466 | enum_mdl_duration mdl_duration_arg); |
467 | /** Set type of lock request. Can be only applied to pending locks. */ |
468 | inline void set_type(enum_mdl_type type_arg) |
469 | { |
470 | DBUG_ASSERT(ticket == NULL); |
471 | type= type_arg; |
472 | } |
473 | |
474 | /** |
475 | Is this a request for a lock which allow data to be updated? |
476 | |
477 | @note This method returns true for MDL_SHARED_UPGRADABLE type of |
478 | lock. Even though this type of lock doesn't allow updates |
479 | it will always be upgraded to one that does. |
480 | */ |
481 | bool is_write_lock_request() const |
482 | { |
483 | return (type >= MDL_SHARED_WRITE && |
484 | type != MDL_SHARED_READ_ONLY); |
485 | } |
486 | |
487 | /* |
488 | This is to work around the ugliness of TABLE_LIST |
489 | compiler-generated assignment operator. It is currently used |
490 | in several places to quickly copy "most" of the members of the |
491 | table list. These places currently never assume that the mdl |
492 | request is carried over to the new TABLE_LIST, or shared |
493 | between lists. |
494 | |
495 | This method does not initialize the instance being assigned! |
496 | Use of init() for initialization after this assignment operator |
497 | is mandatory. Can only be used before the request has been |
498 | granted. |
499 | */ |
500 | MDL_request& operator=(const MDL_request &) |
501 | { |
502 | ticket= NULL; |
503 | /* Do nothing, in particular, don't try to copy the key. */ |
504 | return *this; |
505 | } |
506 | /* Another piece of ugliness for TABLE_LIST constructor */ |
507 | MDL_request() {} |
508 | |
509 | MDL_request(const MDL_request *rhs) |
510 | :type(rhs->type), |
511 | duration(rhs->duration), |
512 | ticket(NULL), |
513 | key(&rhs->key) |
514 | {} |
515 | }; |
516 | |
517 | |
518 | typedef void (*mdl_cached_object_release_hook)(void *); |
519 | |
520 | |
521 | /** |
522 | An abstract class for inspection of a connected |
523 | subgraph of the wait-for graph. |
524 | */ |
525 | |
526 | class MDL_wait_for_graph_visitor |
527 | { |
528 | public: |
529 | virtual bool enter_node(MDL_context *node) = 0; |
530 | virtual void leave_node(MDL_context *node) = 0; |
531 | |
532 | virtual bool inspect_edge(MDL_context *dest) = 0; |
533 | virtual ~MDL_wait_for_graph_visitor(); |
534 | MDL_wait_for_graph_visitor() {} |
535 | }; |
536 | |
537 | /** |
538 | Abstract class representing an edge in the waiters graph |
539 | to be traversed by deadlock detection algorithm. |
540 | */ |
541 | |
542 | class MDL_wait_for_subgraph |
543 | { |
544 | public: |
545 | virtual ~MDL_wait_for_subgraph(); |
546 | |
547 | /** |
548 | Accept a wait-for graph visitor to inspect the node |
549 | this edge is leading to. |
550 | */ |
551 | virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0; |
552 | |
553 | enum enum_deadlock_weight |
554 | { |
555 | DEADLOCK_WEIGHT_DML= 0, |
556 | DEADLOCK_WEIGHT_DDL= 100 |
557 | }; |
558 | /* A helper used to determine which lock request should be aborted. */ |
559 | virtual uint get_deadlock_weight() const = 0; |
560 | }; |
561 | |
562 | |
563 | /** |
564 | A granted metadata lock. |
565 | |
566 | @warning MDL_ticket members are private to the MDL subsystem. |
567 | |
568 | @note Multiple shared locks on a same object are represented by a |
569 | single ticket. The same does not apply for other lock types. |
570 | |
571 | @note There are two groups of MDL_ticket members: |
572 | - "Externally accessible". These members can be accessed from |
573 | threads/contexts different than ticket owner in cases when |
574 | ticket participates in some list of granted or waiting tickets |
575 | for a lock. Therefore one should change these members before |
576 | including then to waiting/granted lists or while holding lock |
577 | protecting those lists. |
578 | - "Context private". Such members are private to thread/context |
579 | owning this ticket. I.e. they should not be accessed from other |
580 | threads/contexts. |
581 | */ |
582 | |
583 | class MDL_ticket : public MDL_wait_for_subgraph |
584 | { |
585 | public: |
586 | /** |
587 | Pointers for participating in the list of lock requests for this context. |
588 | Context private. |
589 | */ |
590 | MDL_ticket *next_in_context; |
591 | MDL_ticket **prev_in_context; |
592 | /** |
593 | Pointers for participating in the list of satisfied/pending requests |
594 | for the lock. Externally accessible. |
595 | */ |
596 | MDL_ticket *next_in_lock; |
597 | MDL_ticket **prev_in_lock; |
598 | public: |
599 | #ifdef WITH_WSREP |
600 | void wsrep_report(bool debug); |
601 | #endif /* WITH_WSREP */ |
602 | bool has_pending_conflicting_lock() const; |
603 | |
604 | MDL_context *get_ctx() const { return m_ctx; } |
605 | bool is_upgradable_or_exclusive() const |
606 | { |
607 | return m_type == MDL_SHARED_UPGRADABLE || |
608 | m_type == MDL_SHARED_NO_WRITE || |
609 | m_type == MDL_SHARED_NO_READ_WRITE || |
610 | m_type == MDL_EXCLUSIVE; |
611 | } |
612 | enum_mdl_type get_type() const { return m_type; } |
613 | MDL_lock *get_lock() const { return m_lock; } |
614 | MDL_key *get_key() const; |
615 | void downgrade_lock(enum_mdl_type type); |
616 | |
617 | bool has_stronger_or_equal_type(enum_mdl_type type) const; |
618 | |
619 | bool is_incompatible_when_granted(enum_mdl_type type) const; |
620 | bool is_incompatible_when_waiting(enum_mdl_type type) const; |
621 | |
622 | /** Implement MDL_wait_for_subgraph interface. */ |
623 | virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor); |
624 | virtual uint get_deadlock_weight() const; |
625 | private: |
626 | friend class MDL_context; |
627 | |
628 | MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg |
629 | #ifndef DBUG_OFF |
630 | , enum_mdl_duration duration_arg |
631 | #endif |
632 | ) |
633 | : m_type(type_arg), |
634 | #ifndef DBUG_OFF |
635 | m_duration(duration_arg), |
636 | #endif |
637 | m_ctx(ctx_arg), |
638 | m_lock(NULL) |
639 | {} |
640 | |
641 | static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg |
642 | #ifndef DBUG_OFF |
643 | , enum_mdl_duration duration_arg |
644 | #endif |
645 | ); |
646 | static void destroy(MDL_ticket *ticket); |
647 | private: |
648 | /** Type of metadata lock. Externally accessible. */ |
649 | enum enum_mdl_type m_type; |
650 | #ifndef DBUG_OFF |
651 | /** |
652 | Duration of lock represented by this ticket. |
653 | Context private. Debug-only. |
654 | */ |
655 | enum_mdl_duration m_duration; |
656 | #endif |
657 | /** |
658 | Context of the owner of the metadata lock ticket. Externally accessible. |
659 | */ |
660 | MDL_context *m_ctx; |
661 | |
662 | /** |
663 | Pointer to the lock object for this lock ticket. Externally accessible. |
664 | */ |
665 | MDL_lock *m_lock; |
666 | |
667 | private: |
668 | MDL_ticket(const MDL_ticket &); /* not implemented */ |
669 | MDL_ticket &operator=(const MDL_ticket &); /* not implemented */ |
670 | }; |
671 | |
672 | |
673 | /** |
674 | Savepoint for MDL context. |
675 | |
676 | Doesn't include metadata locks with explicit duration as |
677 | they are not released during rollback to savepoint. |
678 | */ |
679 | |
680 | class MDL_savepoint |
681 | { |
682 | public: |
683 | MDL_savepoint() {}; |
684 | |
685 | private: |
686 | MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket) |
687 | : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket) |
688 | {} |
689 | |
690 | friend class MDL_context; |
691 | |
692 | private: |
693 | /** |
694 | Pointer to last lock with statement duration which was taken |
695 | before creation of savepoint. |
696 | */ |
697 | MDL_ticket *m_stmt_ticket; |
698 | /** |
699 | Pointer to last lock with transaction duration which was taken |
700 | before creation of savepoint. |
701 | */ |
702 | MDL_ticket *m_trans_ticket; |
703 | }; |
704 | |
705 | |
706 | /** |
707 | A reliable way to wait on an MDL lock. |
708 | */ |
709 | |
710 | class MDL_wait |
711 | { |
712 | public: |
713 | MDL_wait(); |
714 | ~MDL_wait(); |
715 | |
716 | enum enum_wait_status { EMPTY = 0, GRANTED, VICTIM, TIMEOUT, KILLED }; |
717 | |
718 | bool set_status(enum_wait_status result_arg); |
719 | enum_wait_status get_status(); |
720 | void reset_status(); |
721 | enum_wait_status timed_wait(MDL_context_owner *owner, |
722 | struct timespec *abs_timeout, |
723 | bool signal_timeout, |
724 | const PSI_stage_info *wait_state_name); |
725 | private: |
726 | /** |
727 | Condvar which is used for waiting until this context's pending |
728 | request can be satisfied or this thread has to perform actions |
729 | to resolve a potential deadlock (we subscribe to such |
730 | notification by adding a ticket corresponding to the request |
731 | to an appropriate queue of waiters). |
732 | */ |
733 | mysql_mutex_t m_LOCK_wait_status; |
734 | mysql_cond_t m_COND_wait_status; |
735 | enum_wait_status m_wait_status; |
736 | }; |
737 | |
738 | |
739 | typedef I_P_List<MDL_request, I_P_List_adapter<MDL_request, |
740 | &MDL_request::next_in_list, |
741 | &MDL_request::prev_in_list>, |
742 | I_P_List_counter> |
743 | MDL_request_list; |
744 | |
745 | /** |
746 | Context of the owner of metadata locks. I.e. each server |
747 | connection has such a context. |
748 | */ |
749 | |
750 | class MDL_context |
751 | { |
752 | public: |
753 | typedef I_P_List<MDL_ticket, |
754 | I_P_List_adapter<MDL_ticket, |
755 | &MDL_ticket::next_in_context, |
756 | &MDL_ticket::prev_in_context> > |
757 | Ticket_list; |
758 | |
759 | typedef Ticket_list::Iterator Ticket_iterator; |
760 | |
761 | MDL_context(); |
762 | void destroy(); |
763 | |
764 | bool try_acquire_lock(MDL_request *mdl_request); |
765 | bool acquire_lock(MDL_request *mdl_request, double lock_wait_timeout); |
766 | bool acquire_locks(MDL_request_list *requests, double lock_wait_timeout); |
767 | bool upgrade_shared_lock(MDL_ticket *mdl_ticket, |
768 | enum_mdl_type new_type, |
769 | double lock_wait_timeout); |
770 | |
771 | bool clone_ticket(MDL_request *mdl_request); |
772 | |
773 | void release_all_locks_for_name(MDL_ticket *ticket); |
774 | void release_lock(MDL_ticket *ticket); |
775 | |
776 | bool is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace, |
777 | const char *db, const char *name, |
778 | enum_mdl_type mdl_type); |
779 | unsigned long get_lock_owner(MDL_key *mdl_key); |
780 | |
781 | bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket); |
782 | |
783 | inline bool has_locks() const |
784 | { |
785 | return !(m_tickets[MDL_STATEMENT].is_empty() && |
786 | m_tickets[MDL_TRANSACTION].is_empty() && |
787 | m_tickets[MDL_EXPLICIT].is_empty()); |
788 | } |
789 | inline bool has_transactional_locks() const |
790 | { |
791 | return !m_tickets[MDL_TRANSACTION].is_empty(); |
792 | } |
793 | |
794 | MDL_savepoint mdl_savepoint() |
795 | { |
796 | return MDL_savepoint(m_tickets[MDL_STATEMENT].front(), |
797 | m_tickets[MDL_TRANSACTION].front()); |
798 | } |
799 | |
800 | void set_explicit_duration_for_all_locks(); |
801 | void set_transaction_duration_for_all_locks(); |
802 | void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration); |
803 | |
804 | void release_statement_locks(); |
805 | void release_transactional_locks(); |
806 | void release_explicit_locks(); |
807 | void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint); |
808 | |
809 | MDL_context_owner *get_owner() { return m_owner; } |
810 | |
811 | /** @pre Only valid if we started waiting for lock. */ |
812 | inline uint get_deadlock_weight() const |
813 | { return m_waiting_for->get_deadlock_weight(); } |
814 | /** |
815 | Post signal to the context (and wake it up if necessary). |
816 | |
817 | @retval FALSE - Success, signal was posted. |
818 | @retval TRUE - Failure, signal was not posted since context |
819 | already has received some signal or closed |
820 | signal slot. |
821 | */ |
822 | void init(MDL_context_owner *arg) { m_owner= arg; } |
823 | |
824 | void set_needs_thr_lock_abort(bool needs_thr_lock_abort) |
825 | { |
826 | /* |
827 | @note In theory, this member should be modified under protection |
828 | of some lock since it can be accessed from different threads. |
829 | In practice, this is not necessary as code which reads this |
830 | value and so might miss the fact that value was changed will |
831 | always re-try reading it after small timeout and therefore |
832 | will see the new value eventually. |
833 | */ |
834 | m_needs_thr_lock_abort= needs_thr_lock_abort; |
835 | } |
836 | bool get_needs_thr_lock_abort() const |
837 | { |
838 | return m_needs_thr_lock_abort; |
839 | } |
840 | public: |
841 | /** |
842 | If our request for a lock is scheduled, or aborted by the deadlock |
843 | detector, the result is recorded in this class. |
844 | */ |
845 | MDL_wait m_wait; |
846 | private: |
847 | /** |
848 | Lists of all MDL tickets acquired by this connection. |
849 | |
850 | Lists of MDL tickets: |
851 | --------------------- |
852 | The entire set of locks acquired by a connection can be separated |
853 | in three subsets according to their duration: locks released at |
854 | the end of statement, at the end of transaction and locks are |
855 | released explicitly. |
856 | |
857 | Statement and transactional locks are locks with automatic scope. |
858 | They are accumulated in the course of a transaction, and released |
859 | either at the end of uppermost statement (for statement locks) or |
860 | on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT (for transactional |
861 | locks). They must not be (and never are) released manually, |
862 | i.e. with release_lock() call. |
863 | |
864 | Tickets with explicit duration are taken for locks that span |
865 | multiple transactions or savepoints. |
866 | These are: HANDLER SQL locks (HANDLER SQL is |
867 | transaction-agnostic), LOCK TABLES locks (you can COMMIT/etc |
868 | under LOCK TABLES, and the locked tables stay locked), user level |
869 | locks (GET_LOCK()/RELEASE_LOCK() functions) and |
870 | locks implementing "global read lock". |
871 | |
872 | Statement/transactional locks are always prepended to the |
873 | beginning of the appropriate list. In other words, they are |
874 | stored in reverse temporal order. Thus, when we rollback to |
875 | a savepoint, we start popping and releasing tickets from the |
876 | front until we reach the last ticket acquired after the savepoint. |
877 | |
878 | Locks with explicit duration are not stored in any |
879 | particular order, and among each other can be split into |
880 | four sets: |
881 | |
882 | [LOCK TABLES locks] [USER locks] [HANDLER locks] [GLOBAL READ LOCK locks] |
883 | |
884 | The following is known about these sets: |
885 | |
886 | * GLOBAL READ LOCK locks are always stored last. |
887 | This is because one can't say SET GLOBAL read_only=1 or |
888 | FLUSH TABLES WITH READ LOCK if one has locked tables. One can, |
889 | however, LOCK TABLES after having entered the read only mode. |
890 | Note, that subsequent LOCK TABLES statement will unlock the previous |
891 | set of tables, but not the GRL! |
892 | There are no HANDLER locks after GRL locks because |
893 | SET GLOBAL read_only performs a FLUSH TABLES WITH |
894 | READ LOCK internally, and FLUSH TABLES, in turn, implicitly |
895 | closes all open HANDLERs. |
896 | However, one can open a few HANDLERs after entering the |
897 | read only mode. |
898 | * LOCK TABLES locks include intention exclusive locks on |
899 | involved schemas and global intention exclusive lock. |
900 | */ |
901 | Ticket_list m_tickets[MDL_DURATION_END]; |
902 | MDL_context_owner *m_owner; |
903 | /** |
904 | TRUE - if for this context we will break protocol and try to |
905 | acquire table-level locks while having only S lock on |
906 | some table. |
907 | To avoid deadlocks which might occur during concurrent |
908 | upgrade of SNRW lock on such object to X lock we have to |
909 | abort waits for table-level locks for such connections. |
910 | FALSE - Otherwise. |
911 | */ |
912 | bool m_needs_thr_lock_abort; |
913 | |
914 | /** |
915 | Read-write lock protecting m_waiting_for member. |
916 | |
917 | @note The fact that this read-write lock prefers readers is |
918 | important as deadlock detector won't work correctly |
919 | otherwise. @sa Comment for MDL_lock::m_rwlock. |
920 | */ |
921 | mysql_prlock_t m_LOCK_waiting_for; |
922 | /** |
923 | Tell the deadlock detector what metadata lock or table |
924 | definition cache entry this session is waiting for. |
925 | In principle, this is redundant, as information can be found |
926 | by inspecting waiting queues, but we'd very much like it to be |
927 | readily available to the wait-for graph iterator. |
928 | */ |
929 | MDL_wait_for_subgraph *m_waiting_for; |
930 | LF_PINS *m_pins; |
931 | private: |
932 | MDL_ticket *find_ticket(MDL_request *mdl_req, |
933 | enum_mdl_duration *duration); |
934 | void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); |
935 | void release_lock(enum_mdl_duration duration, MDL_ticket *ticket); |
936 | bool try_acquire_lock_impl(MDL_request *mdl_request, |
937 | MDL_ticket **out_ticket); |
938 | bool fix_pins(); |
939 | |
940 | public: |
941 | THD *get_thd() const { return m_owner->get_thd(); } |
942 | bool has_explicit_locks(); |
943 | void find_deadlock(); |
944 | |
945 | ulong get_thread_id() const { return thd_get_thread_id(get_thd()); } |
946 | |
947 | bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor); |
948 | |
949 | /** Inform the deadlock detector there is an edge in the wait-for graph. */ |
950 | void will_wait_for(MDL_wait_for_subgraph *waiting_for_arg) |
951 | { |
952 | mysql_prlock_wrlock(&m_LOCK_waiting_for); |
953 | m_waiting_for= waiting_for_arg; |
954 | mysql_prlock_unlock(&m_LOCK_waiting_for); |
955 | } |
956 | |
957 | /** Remove the wait-for edge from the graph after we're done waiting. */ |
958 | void done_waiting_for() |
959 | { |
960 | mysql_prlock_wrlock(&m_LOCK_waiting_for); |
961 | m_waiting_for= NULL; |
962 | mysql_prlock_unlock(&m_LOCK_waiting_for); |
963 | } |
964 | void lock_deadlock_victim() |
965 | { |
966 | mysql_prlock_rdlock(&m_LOCK_waiting_for); |
967 | } |
968 | void unlock_deadlock_victim() |
969 | { |
970 | mysql_prlock_unlock(&m_LOCK_waiting_for); |
971 | } |
972 | private: |
973 | MDL_context(const MDL_context &rhs); /* not implemented */ |
974 | MDL_context &operator=(MDL_context &rhs); /* not implemented */ |
975 | |
976 | /* metadata_lock_info plugin */ |
977 | friend int i_s_metadata_lock_info_fill_row(MDL_ticket*, void*); |
978 | }; |
979 | |
980 | |
981 | void mdl_init(); |
982 | void mdl_destroy(); |
983 | |
984 | extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd); |
985 | |
986 | /** |
987 | Check if a connection in question is no longer connected. |
988 | |
989 | @details |
990 | Replication apply thread is always connected. Otherwise, |
991 | does a poll on the associated socket to check if the client |
992 | is gone. |
993 | */ |
994 | extern "C" int thd_is_connected(MYSQL_THD thd); |
995 | |
996 | |
997 | /* |
998 | Metadata locking subsystem tries not to grant more than |
999 | max_write_lock_count high-prio, strong locks successively, |
1000 | to avoid starving out weak, low-prio locks. |
1001 | */ |
1002 | extern "C" ulong max_write_lock_count; |
1003 | |
1004 | extern MYSQL_PLUGIN_IMPORT |
1005 | int mdl_iterate(int (*callback)(MDL_ticket *ticket, void *arg), void *arg); |
1006 | #endif |
1007 | |