My Project
|
00001 #ifndef MDL_H 00002 #define MDL_H 00003 /* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; version 2 of the License. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software Foundation, 00016 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ 00017 00018 #if defined(__IBMC__) || defined(__IBMCPP__) 00019 /* Further down, "next_in_lock" and "next_in_context" have the same type, 00020 and in "sql_plist.h" this leads to an identical signature, which causes 00021 problems in function overloading. 00022 */ 00023 #pragma namemangling(v5) 00024 #endif 00025 00026 00027 #include "sql_plist.h" 00028 #include <my_sys.h> 00029 #include <m_string.h> 00030 #include <mysql_com.h> 00031 00032 #include <algorithm> 00033 00034 class THD; 00035 00036 class MDL_context; 00037 class MDL_lock; 00038 class MDL_ticket; 00039 00049 #define ENTER_COND(C, M, S, O) enter_cond(C, M, S, O, __func__, __FILE__, __LINE__) 00050 00056 #define EXIT_COND(S) exit_cond(S, __func__, __FILE__, __LINE__) 00057 00063 class MDL_context_owner 00064 { 00065 public: 00066 virtual ~MDL_context_owner() {} 00067 00083 virtual void enter_cond(mysql_cond_t *cond, mysql_mutex_t *mutex, 00084 const PSI_stage_info *stage, PSI_stage_info *old_stage, 00085 const char *src_function, const char *src_file, 00086 int src_line) = 0; 00087 00098 virtual void exit_cond(const PSI_stage_info *stage, 00099 const char *src_function, const char *src_file, 00100 int src_line) = 0; 00104 virtual int is_killed() = 0; 00105 00110 virtual THD* get_thd() = 0; 00111 00115 virtual bool notify_shared_lock(MDL_context_owner *in_use, 00116 bool needs_thr_lock_abort) = 0; 00117 }; 00118 00126 enum enum_mdl_type { 00127 /* 00128 An intention exclusive metadata lock. Used only for scoped locks. 00129 Owner of this type of lock can acquire upgradable exclusive locks on 00130 individual objects. 00131 Compatible with other IX locks, but is incompatible with scoped S and 00132 X locks. 00133 */ 00134 MDL_INTENTION_EXCLUSIVE= 0, 00135 /* 00136 A shared metadata lock. 00137 To be used in cases when we are interested in object metadata only 00138 and there is no intention to access object data (e.g. for stored 00139 routines or during preparing prepared statements). 00140 We also mis-use this type of lock for open HANDLERs, since lock 00141 acquired by this statement has to be compatible with lock acquired 00142 by LOCK TABLES ... WRITE statement, i.e. SNRW (We can't get by by 00143 acquiring S lock at HANDLER ... OPEN time and upgrading it to SR 00144 lock for HANDLER ... READ as it doesn't solve problem with need 00145 to abort DML statements which wait on table level lock while having 00146 open HANDLER in the same connection). 00147 To avoid deadlock which may occur when SNRW lock is being upgraded to 00148 X lock for table on which there is an active S lock which is owned by 00149 thread which waits in its turn for table-level lock owned by thread 00150 performing upgrade we have to use thr_abort_locks_for_thread() 00151 facility in such situation. 00152 This problem does not arise for locks on stored routines as we don't 00153 use SNRW locks for them. It also does not arise when S locks are used 00154 during PREPARE calls as table-level locks are not acquired in this 00155 case. 00156 */ 00157 MDL_SHARED, 00158 /* 00159 A high priority shared metadata lock. 00160 Used for cases when there is no intention to access object data (i.e. 00161 data in the table). 00162 "High priority" means that, unlike other shared locks, it is granted 00163 ignoring pending requests for exclusive locks. Intended for use in 00164 cases when we only need to access metadata and not data, e.g. when 00165 filling an INFORMATION_SCHEMA table. 00166 Since SH lock is compatible with SNRW lock, the connection that 00167 holds SH lock lock should not try to acquire any kind of table-level 00168 or row-level lock, as this can lead to a deadlock. Moreover, after 00169 acquiring SH lock, the connection should not wait for any other 00170 resource, as it might cause starvation for X locks and a potential 00171 deadlock during upgrade of SNW or SNRW to X lock (e.g. if the 00172 upgrading connection holds the resource that is being waited for). 00173 */ 00174 MDL_SHARED_HIGH_PRIO, 00175 /* 00176 A shared metadata lock for cases when there is an intention to read data 00177 from table. 00178 A connection holding this kind of lock can read table metadata and read 00179 table data (after acquiring appropriate table and row-level locks). 00180 This means that one can only acquire TL_READ, TL_READ_NO_INSERT, and 00181 similar table-level locks on table if one holds SR MDL lock on it. 00182 To be used for tables in SELECTs, subqueries, and LOCK TABLE ... READ 00183 statements. 00184 */ 00185 MDL_SHARED_READ, 00186 /* 00187 A shared metadata lock for cases when there is an intention to modify 00188 (and not just read) data in the table. 00189 A connection holding SW lock can read table metadata and modify or read 00190 table data (after acquiring appropriate table and row-level locks). 00191 To be used for tables to be modified by INSERT, UPDATE, DELETE 00192 statements, but not LOCK TABLE ... WRITE or DDL). Also taken by 00193 SELECT ... FOR UPDATE. 00194 */ 00195 MDL_SHARED_WRITE, 00196 /* 00197 An upgradable shared metadata lock for cases when there is an intention 00198 to modify (and not just read) data in the table. 00199 Can be upgraded to MDL_SHARED_NO_WRITE and MDL_EXCLUSIVE. 00200 A connection holding SU lock can read table metadata and modify or read 00201 table data (after acquiring appropriate table and row-level locks). 00202 To be used for the first phase of ALTER TABLE. 00203 */ 00204 MDL_SHARED_UPGRADABLE, 00205 /* 00206 An upgradable shared metadata lock which blocks all attempts to update 00207 table data, allowing reads. 00208 A connection holding this kind of lock can read table metadata and read 00209 table data. 00210 Can be upgraded to X metadata lock. 00211 Note, that since this type of lock is not compatible with SNRW or SW 00212 lock types, acquiring appropriate engine-level locks for reading 00213 (TL_READ* for MyISAM, shared row locks in InnoDB) should be 00214 contention-free. 00215 To be used for the first phase of ALTER TABLE, when copying data between 00216 tables, to allow concurrent SELECTs from the table, but not UPDATEs. 00217 */ 00218 MDL_SHARED_NO_WRITE, 00219 /* 00220 An upgradable shared metadata lock which allows other connections 00221 to access table metadata, but not data. 00222 It blocks all attempts to read or update table data, while allowing 00223 INFORMATION_SCHEMA and SHOW queries. 00224 A connection holding this kind of lock can read table metadata modify and 00225 read table data. 00226 Can be upgraded to X metadata lock. 00227 To be used for LOCK TABLES WRITE statement. 00228 Not compatible with any other lock type except S and SH. 00229 */ 00230 MDL_SHARED_NO_READ_WRITE, 00231 /* 00232 An exclusive metadata lock. 00233 A connection holding this lock can modify both table's metadata and data. 00234 No other type of metadata lock can be granted while this lock is held. 00235 To be used for CREATE/DROP/RENAME TABLE statements and for execution of 00236 certain phases of other DDL statements. 00237 */ 00238 MDL_EXCLUSIVE, 00239 /* This should be the last !!! */ 00240 MDL_TYPE_END}; 00241 00242 00245 enum enum_mdl_duration { 00250 MDL_STATEMENT= 0, 00255 MDL_TRANSACTION, 00260 MDL_EXPLICIT, 00261 /* This should be the last ! */ 00262 MDL_DURATION_END }; 00263 00264 00266 #define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1) 00267 00268 00278 class MDL_key 00279 { 00280 public: 00281 #ifdef HAVE_PSI_INTERFACE 00282 static void init_psi_keys(); 00283 #endif 00284 00300 enum enum_mdl_namespace { GLOBAL=0, 00301 SCHEMA, 00302 TABLE, 00303 FUNCTION, 00304 PROCEDURE, 00305 TRIGGER, 00306 EVENT, 00307 COMMIT, 00308 /* This should be the last ! */ 00309 NAMESPACE_END }; 00310 00311 const uchar *ptr() const { return (uchar*) m_ptr; } 00312 uint length() const { return m_length; } 00313 00314 const char *db_name() const { return m_ptr + 1; } 00315 uint db_name_length() const { return m_db_name_length; } 00316 00317 const char *name() const { return m_ptr + m_db_name_length + 2; } 00318 uint name_length() const { return m_length - m_db_name_length - 3; } 00319 00320 enum_mdl_namespace mdl_namespace() const 00321 { return (enum_mdl_namespace)(m_ptr[0]); } 00322 00334 void mdl_key_init(enum_mdl_namespace mdl_namespace, 00335 const char *db, const char *name) 00336 { 00337 m_ptr[0]= (char) mdl_namespace; 00338 /* 00339 It is responsibility of caller to ensure that db and object names 00340 are not longer than NAME_LEN. Still we play safe and try to avoid 00341 buffer overruns. 00342 */ 00343 DBUG_ASSERT(strlen(db) <= NAME_LEN && strlen(name) <= NAME_LEN); 00344 m_db_name_length= static_cast<uint16>(strmake(m_ptr + 1, db, NAME_LEN) - 00345 m_ptr - 1); 00346 m_length= static_cast<uint16>(strmake(m_ptr + m_db_name_length + 2, name, 00347 NAME_LEN) - m_ptr + 1); 00348 } 00349 void mdl_key_init(const MDL_key *rhs) 00350 { 00351 memcpy(m_ptr, rhs->m_ptr, rhs->m_length); 00352 m_length= rhs->m_length; 00353 m_db_name_length= rhs->m_db_name_length; 00354 } 00355 bool is_equal(const MDL_key *rhs) const 00356 { 00357 return (m_length == rhs->m_length && 00358 memcmp(m_ptr, rhs->m_ptr, m_length) == 0); 00359 } 00363 int cmp(const MDL_key *rhs) const 00364 { 00365 /* 00366 The key buffer is always '\0'-terminated. Since key 00367 character set is utf-8, we can safely assume that no 00368 character starts with a zero byte. 00369 */ 00370 using std::min; 00371 return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length)); 00372 } 00373 00374 MDL_key(const MDL_key *rhs) 00375 { 00376 mdl_key_init(rhs); 00377 } 00378 MDL_key(enum_mdl_namespace namespace_arg, 00379 const char *db_arg, const char *name_arg) 00380 { 00381 mdl_key_init(namespace_arg, db_arg, name_arg); 00382 } 00383 MDL_key() {} /* To use when part of MDL_request. */ 00384 00389 const PSI_stage_info * get_wait_state_name() const 00390 { 00391 return & m_namespace_to_wait_state_name[(int)mdl_namespace()]; 00392 } 00393 00394 private: 00395 uint16 m_length; 00396 uint16 m_db_name_length; 00397 char m_ptr[MAX_MDLKEY_LENGTH]; 00398 static PSI_stage_info m_namespace_to_wait_state_name[NAMESPACE_END]; 00399 private: 00400 MDL_key(const MDL_key &); /* not implemented */ 00401 MDL_key &operator=(const MDL_key &); /* not implemented */ 00402 }; 00403 00404 00418 class MDL_request 00419 { 00420 public: 00422 enum enum_mdl_type type; 00424 enum enum_mdl_duration duration; 00425 00429 MDL_request *next_in_list; 00430 MDL_request **prev_in_list; 00435 MDL_ticket *ticket; 00436 00438 MDL_key key; 00439 00440 public: 00441 static void *operator new(size_t size, MEM_ROOT *mem_root) throw () 00442 { return alloc_root(mem_root, size); } 00443 static void operator delete(void *ptr, MEM_ROOT *mem_root) {} 00444 00445 void init(MDL_key::enum_mdl_namespace namespace_arg, 00446 const char *db_arg, const char *name_arg, 00447 enum_mdl_type mdl_type_arg, 00448 enum_mdl_duration mdl_duration_arg); 00449 void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg, 00450 enum_mdl_duration mdl_duration_arg); 00452 inline void set_type(enum_mdl_type type_arg) 00453 { 00454 DBUG_ASSERT(ticket == NULL); 00455 type= type_arg; 00456 } 00457 00458 /* 00459 This is to work around the ugliness of TABLE_LIST 00460 compiler-generated assignment operator. It is currently used 00461 in several places to quickly copy "most" of the members of the 00462 table list. These places currently never assume that the mdl 00463 request is carried over to the new TABLE_LIST, or shared 00464 between lists. 00465 00466 This method does not initialize the instance being assigned! 00467 Use of init() for initialization after this assignment operator 00468 is mandatory. Can only be used before the request has been 00469 granted. 00470 */ 00471 MDL_request& operator=(const MDL_request &rhs) 00472 { 00473 ticket= NULL; 00474 /* Do nothing, in particular, don't try to copy the key. */ 00475 return *this; 00476 } 00477 /* Another piece of ugliness for TABLE_LIST constructor */ 00478 MDL_request() {} 00479 00480 MDL_request(const MDL_request *rhs) 00481 :type(rhs->type), 00482 duration(rhs->duration), 00483 ticket(NULL), 00484 key(&rhs->key) 00485 {} 00486 }; 00487 00488 00489 typedef void (*mdl_cached_object_release_hook)(void *); 00490 00491 00497 class MDL_wait_for_graph_visitor 00498 { 00499 public: 00500 virtual bool enter_node(MDL_context *node) = 0; 00501 virtual void leave_node(MDL_context *node) = 0; 00502 00503 virtual bool inspect_edge(MDL_context *dest) = 0; 00504 virtual ~MDL_wait_for_graph_visitor(); 00505 MDL_wait_for_graph_visitor() :m_lock_open_count(0) {} 00506 public: 00515 uint m_lock_open_count; 00516 }; 00517 00523 class MDL_wait_for_subgraph 00524 { 00525 public: 00526 virtual ~MDL_wait_for_subgraph(); 00527 00532 virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0; 00533 00534 enum enum_deadlock_weight 00535 { 00536 DEADLOCK_WEIGHT_DML= 0, 00537 DEADLOCK_WEIGHT_DDL= 100 00538 }; 00539 /* A helper used to determine which lock request should be aborted. */ 00540 virtual uint get_deadlock_weight() const = 0; 00541 }; 00542 00543 00564 class MDL_ticket : public MDL_wait_for_subgraph 00565 { 00566 public: 00571 MDL_ticket *next_in_context; 00572 MDL_ticket **prev_in_context; 00577 MDL_ticket *next_in_lock; 00578 MDL_ticket **prev_in_lock; 00579 public: 00580 bool has_pending_conflicting_lock() const; 00581 00582 MDL_context *get_ctx() const { return m_ctx; } 00583 bool is_upgradable_or_exclusive() const 00584 { 00585 return m_type == MDL_SHARED_UPGRADABLE || 00586 m_type == MDL_SHARED_NO_WRITE || 00587 m_type == MDL_SHARED_NO_READ_WRITE || 00588 m_type == MDL_EXCLUSIVE; 00589 } 00590 enum_mdl_type get_type() const { return m_type; } 00591 MDL_lock *get_lock() const { return m_lock; } 00592 void downgrade_lock(enum_mdl_type type); 00593 00594 bool has_stronger_or_equal_type(enum_mdl_type type) const; 00595 00596 bool is_incompatible_when_granted(enum_mdl_type type) const; 00597 bool is_incompatible_when_waiting(enum_mdl_type type) const; 00598 00600 virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor); 00601 virtual uint get_deadlock_weight() const; 00602 private: 00603 friend class MDL_context; 00604 00605 MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg 00606 #ifndef DBUG_OFF 00607 , enum_mdl_duration duration_arg 00608 #endif 00609 ) 00610 : m_type(type_arg), 00611 #ifndef DBUG_OFF 00612 m_duration(duration_arg), 00613 #endif 00614 m_ctx(ctx_arg), 00615 m_lock(NULL) 00616 {} 00617 00618 static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg 00619 #ifndef DBUG_OFF 00620 , enum_mdl_duration duration_arg 00621 #endif 00622 ); 00623 static void destroy(MDL_ticket *ticket); 00624 private: 00626 enum enum_mdl_type m_type; 00627 #ifndef DBUG_OFF 00628 00632 enum_mdl_duration m_duration; 00633 #endif 00634 00637 MDL_context *m_ctx; 00638 00642 MDL_lock *m_lock; 00643 00644 private: 00645 MDL_ticket(const MDL_ticket &); /* not implemented */ 00646 MDL_ticket &operator=(const MDL_ticket &); /* not implemented */ 00647 }; 00648 00649 00657 class MDL_savepoint 00658 { 00659 public: 00660 MDL_savepoint() {}; 00661 00662 private: 00663 MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket) 00664 : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket) 00665 {} 00666 00667 friend class MDL_context; 00668 00669 private: 00674 MDL_ticket *m_stmt_ticket; 00679 MDL_ticket *m_trans_ticket; 00680 }; 00681 00682 00687 class MDL_wait 00688 { 00689 public: 00690 MDL_wait(); 00691 ~MDL_wait(); 00692 00693 enum enum_wait_status { EMPTY = 0, GRANTED, VICTIM, TIMEOUT, KILLED }; 00694 00695 bool set_status(enum_wait_status result_arg); 00696 enum_wait_status get_status(); 00697 void reset_status(); 00698 enum_wait_status timed_wait(MDL_context_owner *owner, 00699 struct timespec *abs_timeout, 00700 bool signal_timeout, 00701 const PSI_stage_info *wait_state_name); 00702 private: 00710 mysql_mutex_t m_LOCK_wait_status; 00711 mysql_cond_t m_COND_wait_status; 00712 enum_wait_status m_wait_status; 00713 }; 00714 00715 00716 typedef I_P_List<MDL_request, I_P_List_adapter<MDL_request, 00717 &MDL_request::next_in_list, 00718 &MDL_request::prev_in_list>, 00719 I_P_List_counter> 00720 MDL_request_list; 00721 00727 class MDL_context 00728 { 00729 public: 00730 typedef I_P_List<MDL_ticket, 00731 I_P_List_adapter<MDL_ticket, 00732 &MDL_ticket::next_in_context, 00733 &MDL_ticket::prev_in_context> > 00734 Ticket_list; 00735 00736 typedef Ticket_list::Iterator Ticket_iterator; 00737 00738 MDL_context(); 00739 void destroy(); 00740 00741 bool try_acquire_lock(MDL_request *mdl_request); 00742 bool acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout); 00743 bool acquire_locks(MDL_request_list *requests, ulong lock_wait_timeout); 00744 bool upgrade_shared_lock(MDL_ticket *mdl_ticket, 00745 enum_mdl_type new_type, 00746 ulong lock_wait_timeout); 00747 00748 bool clone_ticket(MDL_request *mdl_request); 00749 00750 void release_all_locks_for_name(MDL_ticket *ticket); 00751 void release_lock(MDL_ticket *ticket); 00752 00753 bool is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace, 00754 const char *db, const char *name, 00755 enum_mdl_type mdl_type); 00756 00757 bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket); 00758 00759 inline bool has_locks() const 00760 { 00761 return !(m_tickets[MDL_STATEMENT].is_empty() && 00762 m_tickets[MDL_TRANSACTION].is_empty() && 00763 m_tickets[MDL_EXPLICIT].is_empty()); 00764 } 00765 00766 MDL_savepoint mdl_savepoint() 00767 { 00768 return MDL_savepoint(m_tickets[MDL_STATEMENT].front(), 00769 m_tickets[MDL_TRANSACTION].front()); 00770 } 00771 00772 void set_explicit_duration_for_all_locks(); 00773 void set_transaction_duration_for_all_locks(); 00774 void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration); 00775 00776 void release_statement_locks(); 00777 void release_transactional_locks(); 00778 void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint); 00779 00780 MDL_context_owner *get_owner() { return m_owner; } 00781 00783 inline uint get_deadlock_weight() const 00784 { return m_waiting_for->get_deadlock_weight(); } 00793 void init(MDL_context_owner *arg) { m_owner= arg; } 00794 00795 void set_needs_thr_lock_abort(bool needs_thr_lock_abort) 00796 { 00797 /* 00798 @note In theory, this member should be modified under protection 00799 of some lock since it can be accessed from different threads. 00800 In practice, this is not necessary as code which reads this 00801 value and so might miss the fact that value was changed will 00802 always re-try reading it after small timeout and therefore 00803 will see the new value eventually. 00804 */ 00805 m_needs_thr_lock_abort= needs_thr_lock_abort; 00806 } 00807 bool get_needs_thr_lock_abort() const 00808 { 00809 return m_needs_thr_lock_abort; 00810 } 00811 public: 00816 MDL_wait m_wait; 00817 private: 00872 Ticket_list m_tickets[MDL_DURATION_END]; 00873 MDL_context_owner *m_owner; 00883 bool m_needs_thr_lock_abort; 00884 00892 mysql_prlock_t m_LOCK_waiting_for; 00900 MDL_wait_for_subgraph *m_waiting_for; 00901 private: 00902 THD *get_thd() const { return m_owner->get_thd(); } 00903 MDL_ticket *find_ticket(MDL_request *mdl_req, 00904 enum_mdl_duration *duration); 00905 void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel); 00906 void release_lock(enum_mdl_duration duration, MDL_ticket *ticket); 00907 bool try_acquire_lock_impl(MDL_request *mdl_request, 00908 MDL_ticket **out_ticket); 00909 00910 public: 00911 void find_deadlock(); 00912 00913 bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor); 00914 00916 void will_wait_for(MDL_wait_for_subgraph *waiting_for_arg) 00917 { 00918 mysql_prlock_wrlock(&m_LOCK_waiting_for); 00919 m_waiting_for= waiting_for_arg; 00920 mysql_prlock_unlock(&m_LOCK_waiting_for); 00921 } 00922 00924 void done_waiting_for() 00925 { 00926 mysql_prlock_wrlock(&m_LOCK_waiting_for); 00927 m_waiting_for= NULL; 00928 mysql_prlock_unlock(&m_LOCK_waiting_for); 00929 } 00930 void lock_deadlock_victim() 00931 { 00932 mysql_prlock_rdlock(&m_LOCK_waiting_for); 00933 } 00934 void unlock_deadlock_victim() 00935 { 00936 mysql_prlock_unlock(&m_LOCK_waiting_for); 00937 } 00938 private: 00939 MDL_context(const MDL_context &rhs); /* not implemented */ 00940 MDL_context &operator=(MDL_context &rhs); /* not implemented */ 00941 }; 00942 00943 00944 void mdl_init(); 00945 void mdl_destroy(); 00946 00947 00948 #ifndef DBUG_OFF 00949 extern mysql_mutex_t LOCK_open; 00950 #endif 00951 00952 00953 /* 00954 Start-up parameter for the maximum size of the unused MDL_lock objects cache 00955 and a constant for its default value. 00956 */ 00957 extern ulong mdl_locks_cache_size; 00958 static const ulong MDL_LOCKS_CACHE_SIZE_DEFAULT = 1024; 00959 00960 /* 00961 Start-up parameter for the number of partitions of the hash 00962 containing all the MDL_lock objects and a constant for 00963 its default value. 00964 */ 00965 extern ulong mdl_locks_hash_partitions; 00966 static const ulong MDL_LOCKS_HASH_PARTITIONS_DEFAULT = 8; 00967 00968 /* 00969 Metadata locking subsystem tries not to grant more than 00970 max_write_lock_count high-prio, strong locks successively, 00971 to avoid starving out weak, low-prio locks. 00972 */ 00973 extern "C" ulong max_write_lock_count; 00974 #endif