~ubuntu-branches/ubuntu/precise/mysql-5.5/precise-201203300109

« back to all changes in this revision

Viewing changes to sql/mdl.h

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2011-11-08 11:31:13 UTC
  • Revision ID: package-import@ubuntu.com-20111108113113-3ulw01fvi4vn8m25
Tags: upstream-5.5.17
ImportĀ upstreamĀ versionĀ 5.5.17

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifndef MDL_H
 
2
#define MDL_H
 
3
/* Copyright (c) 2009, 2011, 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
 
16
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
 
17
 
 
18
#if defined(__IBMC__) || defined(__IBMCPP__)
 
19
/* Further down, "next_in_lock" and "next_in_context" have the same type,
 
20
   and in "sql_plist.h" this leads to an identical signature, which causes
 
21
   problems in function overloading.
 
22
*/
 
23
#pragma namemangling(v5)
 
24
#endif
 
25
 
 
26
 
 
27
#include "sql_plist.h"
 
28
#include <my_sys.h>
 
29
#include <m_string.h>
 
30
#include <mysql_com.h>
 
31
 
 
32
class THD;
 
33
 
 
34
class MDL_context;
 
35
class MDL_lock;
 
36
class MDL_ticket;
 
37
 
 
38
/**
 
39
  Type of metadata lock request.
 
40
 
 
41
  @sa Comments for MDL_object_lock::can_grant_lock() and
 
42
      MDL_scoped_lock::can_grant_lock() for details.
 
43
*/
 
44
 
 
45
enum enum_mdl_type {
 
46
  /*
 
47
    An intention exclusive metadata lock. Used only for scoped locks.
 
48
    Owner of this type of lock can acquire upgradable exclusive locks on
 
49
    individual objects.
 
50
    Compatible with other IX locks, but is incompatible with scoped S and
 
51
    X locks.
 
52
  */
 
53
  MDL_INTENTION_EXCLUSIVE= 0,
 
54
  /*
 
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
 
74
    case.
 
75
  */
 
76
  MDL_SHARED,
 
77
  /*
 
78
    A high priority shared metadata lock.
 
79
    Used for cases when there is no intention to access object data (i.e.
 
80
    data in the table).
 
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).
 
92
  */
 
93
  MDL_SHARED_HIGH_PRIO,
 
94
  /*
 
95
    A shared metadata lock for cases when there is an intention to read data
 
96
    from table.
 
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
 
102
    statements.
 
103
  */
 
104
  MDL_SHARED_READ,
 
105
  /*
 
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.
 
113
  */
 
114
  MDL_SHARED_WRITE,
 
115
  /*
 
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
 
119
    table data.
 
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
 
124
    contention-free.
 
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.
 
127
  */
 
128
  MDL_SHARED_NO_WRITE,
 
129
  /*
 
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
 
135
    read table data.
 
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.
 
139
  */
 
140
  MDL_SHARED_NO_READ_WRITE,
 
141
  /*
 
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.
 
147
  */
 
148
  MDL_EXCLUSIVE,
 
149
  /* This should be the last !!! */
 
150
  MDL_TYPE_END};
 
151
 
 
152
 
 
153
/** Duration of metadata lock. */
 
154
 
 
155
enum enum_mdl_duration {
 
156
  /**
 
157
    Locks with statement duration are automatically released at the end
 
158
    of statement or transaction.
 
159
  */
 
160
  MDL_STATEMENT= 0,
 
161
  /**
 
162
    Locks with transaction duration are automatically released at the end
 
163
    of transaction.
 
164
  */
 
165
  MDL_TRANSACTION,
 
166
  /**
 
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().
 
169
  */
 
170
  MDL_EXPLICIT,
 
171
  /* This should be the last ! */
 
172
  MDL_DURATION_END };
 
173
 
 
174
 
 
175
/** Maximal length of key for metadata locking subsystem. */
 
176
#define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1)
 
177
 
 
178
 
 
179
/**
 
180
  Metadata lock object key.
 
181
 
 
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"
 
185
  or "name".
 
186
*/
 
187
 
 
188
class MDL_key
 
189
{
 
190
public:
 
191
  /**
 
192
    Object namespaces.
 
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!
 
195
 
 
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.
 
205
  */
 
206
  enum enum_mdl_namespace { GLOBAL=0,
 
207
                            SCHEMA,
 
208
                            TABLE,
 
209
                            FUNCTION,
 
210
                            PROCEDURE,
 
211
                            TRIGGER,
 
212
                            EVENT,
 
213
                            COMMIT,
 
214
                            /* This should be the last ! */
 
215
                            NAMESPACE_END };
 
216
 
 
217
  const uchar *ptr() const { return (uchar*) m_ptr; }
 
218
  uint length() const { return m_length; }
 
219
 
 
220
  const char *db_name() const { return m_ptr + 1; }
 
221
  uint db_name_length() const { return m_db_name_length; }
 
222
 
 
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; }
 
225
 
 
226
  enum_mdl_namespace mdl_namespace() const
 
227
  { return (enum_mdl_namespace)(m_ptr[0]); }
 
228
 
 
229
  /**
 
230
    Construct a metadata lock key from a triplet (mdl_namespace,
 
231
    database and name).
 
232
 
 
233
    @remark The key for a table is <mdl_namespace>+<database name>+<table name>
 
234
 
 
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.
 
239
  */
 
240
  void mdl_key_init(enum_mdl_namespace mdl_namespace,
 
241
                    const char *db, const char *name)
 
242
  {
 
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);
 
246
  }
 
247
  void mdl_key_init(const MDL_key *rhs)
 
248
  {
 
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;
 
252
  }
 
253
  bool is_equal(const MDL_key *rhs) const
 
254
  {
 
255
    return (m_length == rhs->m_length &&
 
256
            memcmp(m_ptr, rhs->m_ptr, m_length) == 0);
 
257
  }
 
258
  /**
 
259
    Compare two MDL keys lexicographically.
 
260
  */
 
261
  int cmp(const MDL_key *rhs) const
 
262
  {
 
263
    /*
 
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.
 
267
    */
 
268
    return memcmp(m_ptr, rhs->m_ptr, min(m_length, rhs->m_length));
 
269
  }
 
270
 
 
271
  MDL_key(const MDL_key *rhs)
 
272
  {
 
273
    mdl_key_init(rhs);
 
274
  }
 
275
  MDL_key(enum_mdl_namespace namespace_arg,
 
276
          const char *db_arg, const char *name_arg)
 
277
  {
 
278
    mdl_key_init(namespace_arg, db_arg, name_arg);
 
279
  }
 
280
  MDL_key() {} /* To use when part of MDL_request. */
 
281
 
 
282
  /**
 
283
    Get thread state name to be used in case when we have to
 
284
    wait on resource identified by key.
 
285
  */
 
286
  const char * get_wait_state_name() const
 
287
  {
 
288
    return m_namespace_to_wait_state_name[(int)mdl_namespace()];
 
289
  }
 
290
 
 
291
private:
 
292
  uint16 m_length;
 
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];
 
296
private:
 
297
  MDL_key(const MDL_key &);                     /* not implemented */
 
298
  MDL_key &operator=(const MDL_key &);          /* not implemented */
 
299
};
 
300
 
 
301
 
 
302
/**
 
303
  A pending metadata lock request.
 
304
 
 
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.
 
310
 
 
311
  MDL_request is a C structure, you don't need to call a constructor
 
312
  or destructor for it.
 
313
*/
 
314
 
 
315
class MDL_request
 
316
{
 
317
public:
 
318
  /** Type of metadata lock. */
 
319
  enum          enum_mdl_type type;
 
320
  /** Duration for requested lock. */
 
321
  enum enum_mdl_duration duration;
 
322
 
 
323
  /**
 
324
    Pointers for participating in the list of lock requests for this context.
 
325
  */
 
326
  MDL_request *next_in_list;
 
327
  MDL_request **prev_in_list;
 
328
  /**
 
329
    Pointer to the lock ticket object for this lock request.
 
330
    Valid only if this lock request is satisfied.
 
331
  */
 
332
  MDL_ticket *ticket;
 
333
 
 
334
  /** A lock is requested based on a fully qualified name and type. */
 
335
  MDL_key key;
 
336
 
 
337
public:
 
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) {}
 
341
 
 
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)
 
350
  {
 
351
    DBUG_ASSERT(ticket == NULL);
 
352
    type= type_arg;
 
353
  }
 
354
 
 
355
  /*
 
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
 
361
    between lists.
 
362
 
 
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
 
366
    granted.
 
367
  */
 
368
  MDL_request& operator=(const MDL_request &rhs)
 
369
  {
 
370
    ticket= NULL;
 
371
    /* Do nothing, in particular, don't try to copy the key. */
 
372
    return *this;
 
373
  }
 
374
  /* Another piece of ugliness for TABLE_LIST constructor */
 
375
  MDL_request() {}
 
376
 
 
377
  MDL_request(const MDL_request *rhs)
 
378
    :type(rhs->type),
 
379
    duration(rhs->duration),
 
380
    ticket(NULL),
 
381
    key(&rhs->key)
 
382
  {}
 
383
};
 
384
 
 
385
 
 
386
typedef void (*mdl_cached_object_release_hook)(void *);
 
387
 
 
388
 
 
389
/**
 
390
  An abstract class for inspection of a connected
 
391
  subgraph of the wait-for graph.
 
392
*/
 
393
 
 
394
class MDL_wait_for_graph_visitor
 
395
{
 
396
public:
 
397
  virtual bool enter_node(MDL_context *node) = 0;
 
398
  virtual void leave_node(MDL_context *node) = 0;
 
399
 
 
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) {}
 
403
public:
 
404
  /**
 
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.
 
411
  */
 
412
  uint m_lock_open_count;
 
413
};
 
414
 
 
415
/**
 
416
  Abstract class representing an edge in the waiters graph
 
417
  to be traversed by deadlock detection algorithm.
 
418
*/
 
419
 
 
420
class MDL_wait_for_subgraph
 
421
{
 
422
public:
 
423
  virtual ~MDL_wait_for_subgraph();
 
424
 
 
425
  /**
 
426
    Accept a wait-for graph visitor to inspect the node
 
427
    this edge is leading to.
 
428
  */
 
429
  virtual bool accept_visitor(MDL_wait_for_graph_visitor *gvisitor) = 0;
 
430
 
 
431
  enum enum_deadlock_weight
 
432
  {
 
433
    DEADLOCK_WEIGHT_DML= 0,
 
434
    DEADLOCK_WEIGHT_DDL= 100
 
435
  };
 
436
  /* A helper used to determine which lock request should be aborted. */
 
437
  virtual uint get_deadlock_weight() const = 0;
 
438
};
 
439
 
 
440
 
 
441
/**
 
442
  A granted metadata lock.
 
443
 
 
444
  @warning MDL_ticket members are private to the MDL subsystem.
 
445
 
 
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.
 
448
 
 
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
 
458
          threads/contexts.
 
459
*/
 
460
 
 
461
class MDL_ticket : public MDL_wait_for_subgraph
 
462
{
 
463
public:
 
464
  /**
 
465
    Pointers for participating in the list of lock requests for this context.
 
466
    Context private.
 
467
  */
 
468
  MDL_ticket *next_in_context;
 
469
  MDL_ticket **prev_in_context;
 
470
  /**
 
471
    Pointers for participating in the list of satisfied/pending requests
 
472
    for the lock. Externally accessible.
 
473
  */
 
474
  MDL_ticket *next_in_lock;
 
475
  MDL_ticket **prev_in_lock;
 
476
public:
 
477
  bool has_pending_conflicting_lock() const;
 
478
 
 
479
  MDL_context *get_ctx() const { return m_ctx; }
 
480
  bool is_upgradable_or_exclusive() const
 
481
  {
 
482
    return m_type == MDL_SHARED_NO_WRITE ||
 
483
           m_type == MDL_SHARED_NO_READ_WRITE ||
 
484
           m_type == MDL_EXCLUSIVE;
 
485
  }
 
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);
 
489
 
 
490
  bool has_stronger_or_equal_type(enum_mdl_type type) const;
 
491
 
 
492
  bool is_incompatible_when_granted(enum_mdl_type type) const;
 
493
  bool is_incompatible_when_waiting(enum_mdl_type type) const;
 
494
 
 
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;
 
498
private:
 
499
  friend class MDL_context;
 
500
 
 
501
  MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg
 
502
#ifndef DBUG_OFF
 
503
             , enum_mdl_duration duration_arg
 
504
#endif
 
505
            )
 
506
   : m_type(type_arg),
 
507
#ifndef DBUG_OFF
 
508
     m_duration(duration_arg),
 
509
#endif
 
510
     m_ctx(ctx_arg),
 
511
     m_lock(NULL)
 
512
  {}
 
513
 
 
514
  static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg
 
515
#ifndef DBUG_OFF
 
516
                            , enum_mdl_duration duration_arg
 
517
#endif
 
518
                            );
 
519
  static void destroy(MDL_ticket *ticket);
 
520
private:
 
521
  /** Type of metadata lock. Externally accessible. */
 
522
  enum enum_mdl_type m_type;
 
523
#ifndef DBUG_OFF
 
524
  /**
 
525
    Duration of lock represented by this ticket.
 
526
    Context private. Debug-only.
 
527
  */
 
528
  enum_mdl_duration m_duration;
 
529
#endif
 
530
  /**
 
531
    Context of the owner of the metadata lock ticket. Externally accessible.
 
532
  */
 
533
  MDL_context *m_ctx;
 
534
 
 
535
  /**
 
536
    Pointer to the lock object for this lock ticket. Externally accessible.
 
537
  */
 
538
  MDL_lock *m_lock;
 
539
 
 
540
private:
 
541
  MDL_ticket(const MDL_ticket &);               /* not implemented */
 
542
  MDL_ticket &operator=(const MDL_ticket &);    /* not implemented */
 
543
};
 
544
 
 
545
 
 
546
/**
 
547
  Savepoint for MDL context.
 
548
 
 
549
  Doesn't include metadata locks with explicit duration as
 
550
  they are not released during rollback to savepoint.
 
551
*/
 
552
 
 
553
class MDL_savepoint
 
554
{
 
555
public:
 
556
  MDL_savepoint() {};
 
557
 
 
558
private:
 
559
  MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket)
 
560
    : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket)
 
561
  {}
 
562
 
 
563
  friend class MDL_context;
 
564
 
 
565
private:
 
566
  /**
 
567
    Pointer to last lock with statement duration which was taken
 
568
    before creation of savepoint.
 
569
  */
 
570
  MDL_ticket *m_stmt_ticket;
 
571
  /**
 
572
    Pointer to last lock with transaction duration which was taken
 
573
    before creation of savepoint.
 
574
  */
 
575
  MDL_ticket *m_trans_ticket;
 
576
};
 
577
 
 
578
 
 
579
/**
 
580
  A reliable way to wait on an MDL lock.
 
581
*/
 
582
 
 
583
class MDL_wait
 
584
{
 
585
public:
 
586
  MDL_wait();
 
587
  ~MDL_wait();
 
588
 
 
589
  enum enum_wait_status { EMPTY = 0, GRANTED, VICTIM, TIMEOUT, KILLED };
 
590
 
 
591
  bool set_status(enum_wait_status result_arg);
 
592
  enum_wait_status get_status();
 
593
  void reset_status();
 
594
  enum_wait_status timed_wait(THD *thd, struct timespec *abs_timeout,
 
595
                              bool signal_timeout, const char *wait_state_name);
 
596
private:
 
597
  /**
 
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).
 
603
  */
 
604
  mysql_mutex_t m_LOCK_wait_status;
 
605
  mysql_cond_t m_COND_wait_status;
 
606
  enum_wait_status m_wait_status;
 
607
};
 
608
 
 
609
 
 
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>,
 
613
                 I_P_List_counter>
 
614
        MDL_request_list;
 
615
 
 
616
/**
 
617
  Context of the owner of metadata locks. I.e. each server
 
618
  connection has such a context.
 
619
*/
 
620
 
 
621
class MDL_context
 
622
{
 
623
public:
 
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> >
 
628
          Ticket_list;
 
629
 
 
630
  typedef Ticket_list::Iterator Ticket_iterator;
 
631
 
 
632
  MDL_context();
 
633
  void destroy();
 
634
 
 
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);
 
640
 
 
641
  bool clone_ticket(MDL_request *mdl_request);
 
642
 
 
643
  void release_all_locks_for_name(MDL_ticket *ticket);
 
644
  void release_lock(MDL_ticket *ticket);
 
645
 
 
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);
 
649
 
 
650
  bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket);
 
651
 
 
652
  inline bool has_locks() const
 
653
  {
 
654
    return !(m_tickets[MDL_STATEMENT].is_empty() &&
 
655
             m_tickets[MDL_TRANSACTION].is_empty() &&
 
656
             m_tickets[MDL_EXPLICIT].is_empty());
 
657
  }
 
658
 
 
659
  MDL_savepoint mdl_savepoint()
 
660
  {
 
661
    return MDL_savepoint(m_tickets[MDL_STATEMENT].front(),
 
662
                         m_tickets[MDL_TRANSACTION].front());
 
663
  }
 
664
 
 
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);
 
668
 
 
669
  void release_statement_locks();
 
670
  void release_transactional_locks();
 
671
  void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
 
672
 
 
673
  inline THD *get_thd() const { return m_thd; }
 
674
 
 
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(); }
 
678
  /**
 
679
    Post signal to the context (and wake it up if necessary).
 
680
 
 
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
 
684
                    signal slot.
 
685
  */
 
686
  void init(THD *thd_arg) { m_thd= thd_arg; }
 
687
 
 
688
  void set_needs_thr_lock_abort(bool needs_thr_lock_abort)
 
689
  {
 
690
    /*
 
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.
 
697
    */
 
698
    m_needs_thr_lock_abort= needs_thr_lock_abort;
 
699
  }
 
700
  bool get_needs_thr_lock_abort() const
 
701
  {
 
702
    return m_needs_thr_lock_abort;
 
703
  }
 
704
public:
 
705
  /**
 
706
    If our request for a lock is scheduled, or aborted by the deadlock
 
707
    detector, the result is recorded in this class.
 
708
  */
 
709
  MDL_wait m_wait;
 
710
private:
 
711
  /**
 
712
    Lists of all MDL tickets acquired by this connection.
 
713
 
 
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
 
719
    explicitly.
 
720
 
 
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.
 
727
 
 
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".
 
734
 
 
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.
 
740
 
 
741
    Locks with explicit duration stored are not stored in any
 
742
    particular order, and among each other can be split into
 
743
    three sets:
 
744
 
 
745
    [LOCK TABLES locks] [HANDLER locks] [GLOBAL READ LOCK locks]
 
746
 
 
747
    The following is known about these sets:
 
748
 
 
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
 
761
      read only mode.
 
762
    * LOCK TABLES locks include intention exclusive locks on
 
763
      involved schemas and global intention exclusive lock.
 
764
  */
 
765
  Ticket_list m_tickets[MDL_DURATION_END];
 
766
  THD *m_thd;
 
767
  /**
 
768
    TRUE -  if for this context we will break protocol and try to
 
769
            acquire table-level locks while having only S lock on
 
770
            some table.
 
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.
 
774
    FALSE - Otherwise.
 
775
  */
 
776
  bool m_needs_thr_lock_abort;
 
777
 
 
778
  /**
 
779
    Read-write lock protecting m_waiting_for member.
 
780
 
 
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.
 
784
  */
 
785
  mysql_prlock_t m_LOCK_waiting_for;
 
786
  /**
 
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.
 
792
   */
 
793
  MDL_wait_for_subgraph *m_waiting_for;
 
794
private:
 
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);
 
801
 
 
802
public:
 
803
  void find_deadlock();
 
804
 
 
805
  bool visit_subgraph(MDL_wait_for_graph_visitor *dvisitor);
 
806
 
 
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)
 
809
  {
 
810
    mysql_prlock_wrlock(&m_LOCK_waiting_for);
 
811
    m_waiting_for=  waiting_for_arg;
 
812
    mysql_prlock_unlock(&m_LOCK_waiting_for);
 
813
  }
 
814
 
 
815
  /** Remove the wait-for edge from the graph after we're done waiting. */
 
816
  void done_waiting_for()
 
817
  {
 
818
    mysql_prlock_wrlock(&m_LOCK_waiting_for);
 
819
    m_waiting_for= NULL;
 
820
    mysql_prlock_unlock(&m_LOCK_waiting_for);
 
821
  }
 
822
  void lock_deadlock_victim()
 
823
  {
 
824
    mysql_prlock_rdlock(&m_LOCK_waiting_for);
 
825
  }
 
826
  void unlock_deadlock_victim()
 
827
  {
 
828
    mysql_prlock_unlock(&m_LOCK_waiting_for);
 
829
  }
 
830
private:
 
831
  MDL_context(const MDL_context &rhs);          /* not implemented */
 
832
  MDL_context &operator=(MDL_context &rhs);     /* not implemented */
 
833
};
 
834
 
 
835
 
 
836
void mdl_init();
 
837
void mdl_destroy();
 
838
 
 
839
 
 
840
/*
 
841
  Functions in the server's kernel used by metadata locking subsystem.
 
842
*/
 
843
 
 
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);
 
849
 
 
850
#ifndef DBUG_OFF
 
851
extern mysql_mutex_t LOCK_open;
 
852
#endif
 
853
 
 
854
#endif