3
/* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
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.
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.
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
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
18
#if defined(__IBMC__) || defined(__IBMCPP__)
19
/* Further down, "next_in_lock" and "next_in_context" have the same type,
20
and in "sql_plist.h" this leads to an identical signature, which causes
21
problems in function overloading.
23
#pragma namemangling(v5)
27
#include "sql_plist.h"
30
#include <mysql_com.h>
39
Type of metadata lock request.
41
@sa Comments for MDL_object_lock::can_grant_lock() and
42
MDL_scoped_lock::can_grant_lock() for details.
47
An intention exclusive metadata lock. Used only for scoped locks.
48
Owner of this type of lock can acquire upgradable exclusive locks on
50
Compatible with other IX locks, but is incompatible with scoped S and
53
MDL_INTENTION_EXCLUSIVE= 0,
55
A shared metadata lock.
56
To be used in cases when we are interested in object metadata only
57
and there is no intention to access object data (e.g. for stored
58
routines or during preparing prepared statements).
59
We also mis-use this type of lock for open HANDLERs, since lock
60
acquired by this statement has to be compatible with lock acquired
61
by LOCK TABLES ... WRITE statement, i.e. SNRW (We can't get by by
62
acquiring S lock at HANDLER ... OPEN time and upgrading it to SR
63
lock for HANDLER ... READ as it doesn't solve problem with need
64
to abort DML statements which wait on table level lock while having
65
open HANDLER in the same connection).
66
To avoid deadlock which may occur when SNRW lock is being upgraded to
67
X lock for table on which there is an active S lock which is owned by
68
thread which waits in its turn for table-level lock owned by thread
69
performing upgrade we have to use thr_abort_locks_for_thread()
70
facility in such situation.
71
This problem does not arise for locks on stored routines as we don't
72
use SNRW locks for them. It also does not arise when S locks are used
73
during PREPARE calls as table-level locks are not acquired in this
78
A high priority shared metadata lock.
79
Used for cases when there is no intention to access object data (i.e.
81
"High priority" means that, unlike other shared locks, it is granted
82
ignoring pending requests for exclusive locks. Intended for use in
83
cases when we only need to access metadata and not data, e.g. when
84
filling an INFORMATION_SCHEMA table.
85
Since SH lock is compatible with SNRW lock, the connection that
86
holds SH lock lock should not try to acquire any kind of table-level
87
or row-level lock, as this can lead to a deadlock. Moreover, after
88
acquiring SH lock, the connection should not wait for any other
89
resource, as it might cause starvation for X locks and a potential
90
deadlock during upgrade of SNW or SNRW to X lock (e.g. if the
91
upgrading connection holds the resource that is being waited for).
95
A shared metadata lock for cases when there is an intention to read data
97
A connection holding this kind of lock can read table metadata and read
98
table data (after acquiring appropriate table and row-level locks).
99
This means that one can only acquire TL_READ, TL_READ_NO_INSERT, and
100
similar table-level locks on table if one holds SR MDL lock on it.
101
To be used for tables in SELECTs, subqueries, and LOCK TABLE ... READ
106
A shared metadata lock for cases when there is an intention to modify
107
(and not just read) data in the table.
108
A connection holding SW lock can read table metadata and modify or read
109
table data (after acquiring appropriate table and row-level locks).
110
To be used for tables to be modified by INSERT, UPDATE, DELETE
111
statements, but not LOCK TABLE ... WRITE or DDL). Also taken by
112
SELECT ... FOR UPDATE.
116
An upgradable shared metadata lock which blocks all attempts to update
117
table data, allowing reads.
118
A connection holding this kind of lock can read table metadata and read
120
Can be upgraded to X metadata lock.
121
Note, that since this type of lock is not compatible with SNRW or SW
122
lock types, acquiring appropriate engine-level locks for reading
123
(TL_READ* for MyISAM, shared row locks in InnoDB) should be
125
To be used for the first phase of ALTER TABLE, when copying data between
126
tables, to allow concurrent SELECTs from the table, but not UPDATEs.
130
An upgradable shared metadata lock which allows other connections
131
to access table metadata, but not data.
132
It blocks all attempts to read or update table data, while allowing
133
INFORMATION_SCHEMA and SHOW queries.
134
A connection holding this kind of lock can read table metadata modify and
136
Can be upgraded to X metadata lock.
137
To be used for LOCK TABLES WRITE statement.
138
Not compatible with any other lock type except S and SH.
140
MDL_SHARED_NO_READ_WRITE,
142
An exclusive metadata lock.
143
A connection holding this lock can modify both table's metadata and data.
144
No other type of metadata lock can be granted while this lock is held.
145
To be used for CREATE/DROP/RENAME TABLE statements and for execution of
146
certain phases of other DDL statements.
149
/* This should be the last !!! */
153
/** Duration of metadata lock. */
155
enum enum_mdl_duration {
157
Locks with statement duration are automatically released at the end
158
of statement or transaction.
162
Locks with transaction duration are automatically released at the end
167
Locks with explicit duration survive the end of statement and transaction.
168
They have to be released explicitly by calling MDL_context::release_lock().
171
/* This should be the last ! */
175
/** Maximal length of key for metadata locking subsystem. */
176
#define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1)
180
Metadata lock object key.
182
A lock is requested or granted based on a fully qualified name and type.
183
E.g. They key for a table consists of <0 (=table)>+<database>+<table name>.
184
Elsewhere in the comments this triple will be referred to simply as "key"
193
Sic: when adding a new member to this enum make sure to
194
update m_namespace_to_wait_state_name array in mdl.cc!
196
Different types of objects exist in different namespaces
197
- TABLE is for tables and views.
198
- FUNCTION is for stored functions.
199
- PROCEDURE is for stored procedures.
200
- TRIGGER is for triggers.
201
- EVENT is for event scheduler events
202
Note that although there isn't metadata locking on triggers,
203
it's necessary to have a separate namespace for them since
204
MDL_key is also used outside of the MDL subsystem.
206
enum enum_mdl_namespace { GLOBAL=0,
214
/* This should be the last ! */
217
const uchar *ptr() const { return (uchar*) m_ptr; }
218
uint length() const { return m_length; }
220
const char *db_name() const { return m_ptr + 1; }
221
uint db_name_length() const { return m_db_name_length; }
223
const char *name() const { return m_ptr + m_db_name_length + 2; }
224
uint name_length() const { return m_length - m_db_name_length - 3; }
226
enum_mdl_namespace mdl_namespace() const
227
{ return (enum_mdl_namespace)(m_ptr[0]); }
230
Construct a metadata lock key from a triplet (mdl_namespace,
233
@remark The key for a table is <mdl_namespace>+<database name>+<table name>
235
@param mdl_namespace Id of namespace of object to be locked
236
@param db Name of database to which the object belongs
237
@param name Name of of the object
238
@param key Where to store the the MDL key.
240
void mdl_key_init(enum_mdl_namespace mdl_namespace,
241
const char *db, const char *name)
243
m_ptr[0]= (char) mdl_namespace;
244
m_db_name_length= (uint16) (strmov(m_ptr + 1, db) - m_ptr - 1);
245
m_length= (uint16) (strmov(m_ptr + m_db_name_length + 2, name) - m_ptr + 1);
247
void mdl_key_init(const MDL_key *rhs)
249
memcpy(m_ptr, rhs->m_ptr, rhs->m_length);
250
m_length= rhs->m_length;
251
m_db_name_length= rhs->m_db_name_length;
253
bool is_equal(const MDL_key *rhs) const
255
return (m_length == rhs->m_length &&
256
memcmp(m_ptr, rhs->m_ptr, m_length) == 0);
259
Compare two MDL keys lexicographically.
261
int cmp(const MDL_key *rhs) const
264
The key buffer is always '\0'-terminated. Since key
265
character set is utf-8, we can safely assume that no
266
character starts with a zero byte.
268
return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length));
271
MDL_key(const MDL_key *rhs)
275
MDL_key(enum_mdl_namespace namespace_arg,
276
const char *db_arg, const char *name_arg)
278
mdl_key_init(namespace_arg, db_arg, name_arg);
280
MDL_key() {} /* To use when part of MDL_request. */
283
Get thread state name to be used in case when we have to
284
wait on resource identified by key.
286
const char * get_wait_state_name() const
288
return m_namespace_to_wait_state_name[(int)mdl_namespace()];
293
uint16 m_db_name_length;
294
char m_ptr[MAX_MDLKEY_LENGTH];
295
static const char * m_namespace_to_wait_state_name[NAMESPACE_END];
297
MDL_key(const MDL_key &); /* not implemented */
298
MDL_key &operator=(const MDL_key &); /* not implemented */
303
A pending metadata lock request.
305
A lock request and a granted metadata lock are represented by
306
different classes because they have different allocation
307
sites and hence different lifetimes. The allocation of lock requests is
308
controlled from outside of the MDL subsystem, while allocation of granted
309
locks (tickets) is controlled within the MDL subsystem.
311
MDL_request is a C structure, you don't need to call a constructor
312
or destructor for it.
318
/** Type of metadata lock. */
319
enum enum_mdl_type type;
320
/** Duration for requested lock. */
321
enum enum_mdl_duration duration;
324
Pointers for participating in the list of lock requests for this context.
326
MDL_request *next_in_list;
327
MDL_request **prev_in_list;
329
Pointer to the lock ticket object for this lock request.
330
Valid only if this lock request is satisfied.
334
/** A lock is requested based on a fully qualified name and type. */
338
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
339
{ return alloc_root(mem_root, size); }
340
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
342
void init(MDL_key::enum_mdl_namespace namespace_arg,
343
const char *db_arg, const char *name_arg,
344
enum_mdl_type mdl_type_arg,
345
enum_mdl_duration mdl_duration_arg);
346
void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg,
347
enum_mdl_duration mdl_duration_arg);
348
/** Set type of lock request. Can be only applied to pending locks. */
349
inline void set_type(enum_mdl_type type_arg)
351
DBUG_ASSERT(ticket == NULL);
356
This is to work around the ugliness of TABLE_LIST
357
compiler-generated assignment operator. It is currently used
358
in several places to quickly copy "most" of the members of the
359
table list. These places currently never assume that the mdl
360
request is carried over to the new TABLE_LIST, or shared
363
This method does not initialize the instance being assigned!
364
Use of init() for initialization after this assignment operator
365
is mandatory. Can only be used before the request has been
368
MDL_request& operator=(const MDL_request &rhs)
371
/* Do nothing, in particular, don't try to copy the key. */
374
/* Another piece of ugliness for TABLE_LIST constructor */
377
MDL_request(const MDL_request *rhs)
379
duration(rhs->duration),
386
typedef void (*mdl_cached_object_release_hook)(void *);
390
An abstract class for inspection of a connected
391
subgraph of the wait-for graph.
394
class MDL_wait_for_graph_visitor
397
virtual bool enter_node(MDL_context *node) = 0;
398
virtual void leave_node(MDL_context *node) = 0;
400
virtual bool inspect_edge(MDL_context *dest) = 0;
401
virtual ~MDL_wait_for_graph_visitor();
402
MDL_wait_for_graph_visitor() :m_lock_open_count(0) {}
405
XXX, hack: During deadlock search, we may need to
406
inspect TABLE_SHAREs and acquire LOCK_open. Since
407
LOCK_open is not a recursive mutex, count here how many
408
times we "took" it (but only take and release once).
409
Not using a native recursive mutex or rwlock in 5.5 for
410
LOCK_open since it has significant performance impacts.
412
uint m_lock_open_count;
416
Abstract class representing an edge in the waiters graph
417
to be traversed by deadlock detection algorithm.
420
class MDL_wait_for_subgraph
423
virtual ~MDL_wait_for_subgraph();
426
Accept a wait-for graph visitor to inspect the node
427
this edge is leading to.
429
virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0;
431
enum enum_deadlock_weight
433
DEADLOCK_WEIGHT_DML= 0,
434
DEADLOCK_WEIGHT_DDL= 100
436
/* A helper used to determine which lock request should be aborted. */
437
virtual uint get_deadlock_weight() const = 0;
442
A granted metadata lock.
444
@warning MDL_ticket members are private to the MDL subsystem.
446
@note Multiple shared locks on a same object are represented by a
447
single ticket. The same does not apply for other lock types.
449
@note There are two groups of MDL_ticket members:
450
- "Externally accessible". These members can be accessed from
451
threads/contexts different than ticket owner in cases when
452
ticket participates in some list of granted or waiting tickets
453
for a lock. Therefore one should change these members before
454
including then to waiting/granted lists or while holding lock
455
protecting those lists.
456
- "Context private". Such members are private to thread/context
457
owning this ticket. I.e. they should not be accessed from other
461
class MDL_ticket : public MDL_wait_for_subgraph
465
Pointers for participating in the list of lock requests for this context.
468
MDL_ticket *next_in_context;
469
MDL_ticket **prev_in_context;
471
Pointers for participating in the list of satisfied/pending requests
472
for the lock. Externally accessible.
474
MDL_ticket *next_in_lock;
475
MDL_ticket **prev_in_lock;
477
bool has_pending_conflicting_lock() const;
479
MDL_context *get_ctx() const { return m_ctx; }
480
bool is_upgradable_or_exclusive() const
482
return m_type == MDL_SHARED_NO_WRITE ||
483
m_type == MDL_SHARED_NO_READ_WRITE ||
484
m_type == MDL_EXCLUSIVE;
486
enum_mdl_type get_type() const { return m_type; }
487
MDL_lock *get_lock() const { return m_lock; }
488
void downgrade_exclusive_lock(enum_mdl_type type);
490
bool has_stronger_or_equal_type(enum_mdl_type type) const;
492
bool is_incompatible_when_granted(enum_mdl_type type) const;
493
bool is_incompatible_when_waiting(enum_mdl_type type) const;
495
/** Implement MDL_wait_for_subgraph interface. */
496
virtual bool accept_visitor(MDL_wait_for_graph_visitor *dvisitor);
497
virtual uint get_deadlock_weight() const;
499
friend class MDL_context;
501
MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg
503
, enum_mdl_duration duration_arg
508
m_duration(duration_arg),
514
static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg
516
, enum_mdl_duration duration_arg
519
static void destroy(MDL_ticket *ticket);
521
/** Type of metadata lock. Externally accessible. */
522
enum enum_mdl_type m_type;
525
Duration of lock represented by this ticket.
526
Context private. Debug-only.
528
enum_mdl_duration m_duration;
531
Context of the owner of the metadata lock ticket. Externally accessible.
536
Pointer to the lock object for this lock ticket. Externally accessible.
541
MDL_ticket(const MDL_ticket &); /* not implemented */
542
MDL_ticket &operator=(const MDL_ticket &); /* not implemented */
547
Savepoint for MDL context.
549
Doesn't include metadata locks with explicit duration as
550
they are not released during rollback to savepoint.
559
MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket)
560
: m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket)
563
friend class MDL_context;
567
Pointer to last lock with statement duration which was taken
568
before creation of savepoint.
570
MDL_ticket *m_stmt_ticket;
572
Pointer to last lock with transaction duration which was taken
573
before creation of savepoint.
575
MDL_ticket *m_trans_ticket;
580
A reliable way to wait on an MDL lock.
589
enum enum_wait_status { EMPTY = 0, GRANTED, VICTIM, TIMEOUT, KILLED };
591
bool set_status(enum_wait_status result_arg);
592
enum_wait_status get_status();
594
enum_wait_status timed_wait(THD *thd, struct timespec *abs_timeout,
595
bool signal_timeout, const char *wait_state_name);
598
Condvar which is used for waiting until this context's pending
599
request can be satisfied or this thread has to perform actions
600
to resolve a potential deadlock (we subscribe to such
601
notification by adding a ticket corresponding to the request
602
to an appropriate queue of waiters).
604
mysql_mutex_t m_LOCK_wait_status;
605
mysql_cond_t m_COND_wait_status;
606
enum_wait_status m_wait_status;
610
typedef I_P_List<MDL_request, I_P_List_adapter<MDL_request,
611
&MDL_request::next_in_list,
612
&MDL_request::prev_in_list>,
617
Context of the owner of metadata locks. I.e. each server
618
connection has such a context.
624
typedef I_P_List<MDL_ticket,
625
I_P_List_adapter<MDL_ticket,
626
&MDL_ticket::next_in_context,
627
&MDL_ticket::prev_in_context> >
630
typedef Ticket_list::Iterator Ticket_iterator;
635
bool try_acquire_lock(MDL_request *mdl_request);
636
bool acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout);
637
bool acquire_locks(MDL_request_list *requests, ulong lock_wait_timeout);
638
bool upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket,
639
ulong lock_wait_timeout);
641
bool clone_ticket(MDL_request *mdl_request);
643
void release_all_locks_for_name(MDL_ticket *ticket);
644
void release_lock(MDL_ticket *ticket);
646
bool is_lock_owner(MDL_key::enum_mdl_namespace mdl_namespace,
647
const char *db, const char *name,
648
enum_mdl_type mdl_type);
650
bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket);
652
inline bool has_locks() const
654
return !(m_tickets[MDL_STATEMENT].is_empty() &&
655
m_tickets[MDL_TRANSACTION].is_empty() &&
656
m_tickets[MDL_EXPLICIT].is_empty());
659
MDL_savepoint mdl_savepoint()
661
return MDL_savepoint(m_tickets[MDL_STATEMENT].front(),
662
m_tickets[MDL_TRANSACTION].front());
665
void set_explicit_duration_for_all_locks();
666
void set_transaction_duration_for_all_locks();
667
void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration);
669
void release_statement_locks();
670
void release_transactional_locks();
671
void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
673
inline THD *get_thd() const { return m_thd; }
675
/** @pre Only valid if we started waiting for lock. */
676
inline uint get_deadlock_weight() const
677
{ return m_waiting_for->get_deadlock_weight(); }
679
Post signal to the context (and wake it up if necessary).
681
@retval FALSE - Success, signal was posted.
682
@retval TRUE - Failure, signal was not posted since context
683
already has received some signal or closed
686
void init(THD *thd_arg) { m_thd= thd_arg; }
688
void set_needs_thr_lock_abort(bool needs_thr_lock_abort)
691
@note In theory, this member should be modified under protection
692
of some lock since it can be accessed from different threads.
693
In practice, this is not necessary as code which reads this
694
value and so might miss the fact that value was changed will
695
always re-try reading it after small timeout and therefore
696
will see the new value eventually.
698
m_needs_thr_lock_abort= needs_thr_lock_abort;
700
bool get_needs_thr_lock_abort() const
702
return m_needs_thr_lock_abort;
706
If our request for a lock is scheduled, or aborted by the deadlock
707
detector, the result is recorded in this class.
712
Lists of all MDL tickets acquired by this connection.
714
Lists of MDL tickets:
715
---------------------
716
The entire set of locks acquired by a connection can be separated
717
in three subsets according to their: locks released at the end of
718
statement, at the end of transaction and locks are released
721
Statement and transactional locks are locks with automatic scope.
722
They are accumulated in the course of a transaction, and released
723
either at the end of uppermost statement (for statement locks) or
724
on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT (for transactional
725
locks). They must not be (and never are) released manually,
726
i.e. with release_lock() call.
728
Locks with explicit duration are taken for locks that span
729
multiple transactions or savepoints.
730
These are: HANDLER SQL locks (HANDLER SQL is
731
transaction-agnostic), LOCK TABLES locks (you can COMMIT/etc
732
under LOCK TABLES, and the locked tables stay locked), and
733
locks implementing "global read lock".
735
Statement/transactional locks are always prepended to the
736
beginning of the appropriate list. In other words, they are
737
stored in reverse temporal order. Thus, when we rollback to
738
a savepoint, we start popping and releasing tickets from the
739
front until we reach the last ticket acquired after the savepoint.
741
Locks with explicit duration stored are not stored in any
742
particular order, and among each other can be split into
745
[LOCK TABLES locks] [HANDLER locks] [GLOBAL READ LOCK locks]
747
The following is known about these sets:
749
* GLOBAL READ LOCK locks are always stored after LOCK TABLES
750
locks and after HANDLER locks. This is because one can't say
751
SET GLOBAL read_only=1 or FLUSH TABLES WITH READ LOCK
752
if one has locked tables. One can, however, LOCK TABLES
753
after having entered the read only mode. Note, that
754
subsequent LOCK TABLES statement will unlock the previous
755
set of tables, but not the GRL!
756
There are no HANDLER locks after GRL locks because
757
SET GLOBAL read_only performs a FLUSH TABLES WITH
758
READ LOCK internally, and FLUSH TABLES, in turn, implicitly
759
closes all open HANDLERs.
760
However, one can open a few HANDLERs after entering the
762
* LOCK TABLES locks include intention exclusive locks on
763
involved schemas and global intention exclusive lock.
765
Ticket_list m_tickets[MDL_DURATION_END];
768
TRUE - if for this context we will break protocol and try to
769
acquire table-level locks while having only S lock on
771
To avoid deadlocks which might occur during concurrent
772
upgrade of SNRW lock on such object to X lock we have to
773
abort waits for table-level locks for such connections.
776
bool m_needs_thr_lock_abort;
779
Read-write lock protecting m_waiting_for member.
781
@note The fact that this read-write lock prefers readers is
782
important as deadlock detector won't work correctly
783
otherwise. @sa Comment for MDL_lock::m_rwlock.
785
mysql_prlock_t m_LOCK_waiting_for;
787
Tell the deadlock detector what metadata lock or table
788
definition cache entry this session is waiting for.
789
In principle, this is redundant, as information can be found
790
by inspecting waiting queues, but we'd very much like it to be
791
readily available to the wait-for graph iterator.
793
MDL_wait_for_subgraph *m_waiting_for;
795
MDL_ticket *find_ticket(MDL_request *mdl_req,
796
enum_mdl_duration *duration);
797
void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel);
798
void release_lock(enum_mdl_duration duration, MDL_ticket *ticket);
799
bool try_acquire_lock_impl(MDL_request *mdl_request,
800
MDL_ticket **out_ticket);
803
void find_deadlock();
805
bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor);
807
/** Inform the deadlock detector there is an edge in the wait-for graph. */
808
void will_wait_for(MDL_wait_for_subgraph *waiting_for_arg)
810
mysql_prlock_wrlock(&m_LOCK_waiting_for);
811
m_waiting_for= waiting_for_arg;
812
mysql_prlock_unlock(&m_LOCK_waiting_for);
815
/** Remove the wait-for edge from the graph after we're done waiting. */
816
void done_waiting_for()
818
mysql_prlock_wrlock(&m_LOCK_waiting_for);
820
mysql_prlock_unlock(&m_LOCK_waiting_for);
822
void lock_deadlock_victim()
824
mysql_prlock_rdlock(&m_LOCK_waiting_for);
826
void unlock_deadlock_victim()
828
mysql_prlock_unlock(&m_LOCK_waiting_for);
831
MDL_context(const MDL_context &rhs); /* not implemented */
832
MDL_context &operator=(MDL_context &rhs); /* not implemented */
841
Functions in the server's kernel used by metadata locking subsystem.
844
extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
845
bool needs_thr_lock_abort);
846
extern "C" const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond,
847
mysql_mutex_t *mutex, const char *msg);
848
extern "C" void thd_exit_cond(MYSQL_THD thd, const char *old_msg);
851
extern mysql_mutex_t LOCK_open;