| 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 | |