20
20
#include <mysqld_error.h>
22
#ifdef HAVE_PSI_INTERFACE
23
static PSI_mutex_key key_MDL_map_mutex;
24
static PSI_mutex_key key_MDL_context_signal_mutex;
26
static PSI_mutex_info all_mdl_mutexes[]=
28
{ &key_MDL_map_mutex, "MDL_map::mutex", PSI_FLAG_GLOBAL},
29
{ &key_MDL_context_signal_mutex, "MDL_context::signal", 0}
32
static PSI_rwlock_key key_MDL_lock_rwlock;
33
static PSI_rwlock_key key_MDL_context_waiting_for_rwlock;
35
static PSI_rwlock_info all_mdl_rwlocks[]=
37
{ &key_MDL_lock_rwlock, "MDL_lock::rwlock", 0},
38
{ &key_MDL_context_waiting_for_rwlock, "MDL_context::waiting_for_lock", 0}
41
static PSI_cond_key key_MDL_context_signal_cond;
43
static PSI_cond_info all_mdl_conds[]=
45
{ &key_MDL_context_signal_cond, "MDL_context::signal", 0}
49
Initialise all the performance schema instrumentation points
50
used by the MDL subsystem.
52
static void init_mdl_psi_keys(void)
54
const char *category= "sql";
57
if (PSI_server == NULL)
60
count= array_elements(all_mdl_mutexes);
61
PSI_server->register_mutex(category, all_mdl_mutexes, count);
63
count= array_elements(all_mdl_rwlocks);
64
PSI_server->register_rwlock(category, all_mdl_rwlocks, count);
66
count= array_elements(all_mdl_conds);
67
PSI_server->register_cond(category, all_mdl_conds, count);
69
#endif /* HAVE_PSI_INTERFACE */
23
71
void notify_shared_lock(THD *thd, MDL_ticket *conflicting_ticket);
149
197
Read-write lock protecting this lock context.
151
TODO/FIXME: Replace with RW-lock which will prefer readers
152
on all platforms and not only on Linux.
199
@note The fact that we use read-write lock prefers readers here is
200
important as deadlock detector won't work correctly otherwise.
202
For example, imagine that we have following waiters graph:
204
ctxA -> obj1 -> ctxB -> obj1 -|
206
|----------------------------|
208
and both ctxA and ctxB start deadlock detection process:
210
ctxA read-locks obj1 ctxB read-locks obj2
211
ctxA goes deeper ctxB goes deeper
213
Now ctxC comes in who wants to start waiting on obj1, also
214
ctxD comes in who wants to start waiting on obj2.
216
ctxC tries to write-lock obj1 ctxD tries to write-lock obj2
217
ctxC is blocked ctxD is blocked
219
Now ctxA and ctxB resume their search:
221
ctxA tries to read-lock obj2 ctxB tries to read-lock obj1
223
If m_rwlock prefers writes (or fair) both ctxA and ctxB would be
224
blocked because of pending write locks from ctxD and ctxC
225
correspondingly. Thus we will get a deadlock in deadlock detector.
226
If m_wrlock prefers readers (actually ignoring pending writers is
227
enough) ctxA and ctxB will continue and no deadlock will occur.
229
mysql_prlock_t m_rwlock;
156
231
bool is_empty() const
213
288
m_ref_release(0),
214
289
m_is_destroyed(FALSE)
216
my_rwlock_init(&m_rwlock, NULL);
291
mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock);
219
294
virtual ~MDL_lock()
221
rwlock_destroy(&m_rwlock);
296
mysql_prlock_destroy(&m_rwlock);
223
298
inline static void destroy(MDL_lock *lock);
367
447
void MDL_map::init()
369
mysql_mutex_init(NULL /* pfs key */,&m_mutex, NULL);
449
mysql_mutex_init(key_MDL_map_mutex, &m_mutex, NULL);
370
450
my_hash_init(&m_locks, &my_charset_bin, 16 /* FIXME */, 0, 0,
371
451
mdl_locks_key, 0, 0);
496
576
uint ref_usage= lock->m_ref_usage;
497
577
uint ref_release= lock->m_ref_release;
498
rw_unlock(&lock->m_rwlock);
578
mysql_prlock_unlock(&lock->m_rwlock);
499
579
if (ref_usage == ref_release)
500
580
MDL_lock::destroy(lock);
538
618
lock->m_is_destroyed= TRUE;
539
619
ref_usage= lock->m_ref_usage;
540
620
ref_release= lock->m_ref_release;
541
rw_unlock(&lock->m_rwlock);
621
mysql_prlock_unlock(&lock->m_rwlock);
542
622
mysql_mutex_unlock(&m_mutex);
543
623
if (ref_usage == ref_release)
544
624
MDL_lock::destroy(lock);
559
639
m_deadlock_weight(0),
560
640
m_signal(NO_WAKE_UP)
562
my_rwlock_init(&m_waiting_for_lock, NULL);
563
mysql_mutex_init(NULL /* pfs key */, &m_signal_lock, NULL);
564
mysql_cond_init(NULL /* pfs key */, &m_signal_cond, NULL);
642
mysql_prlock_init(key_MDL_context_waiting_for_rwlock, &m_waiting_for_lock);
643
mysql_mutex_init(key_MDL_context_signal_mutex, &m_signal_lock, NULL);
644
mysql_cond_init(key_MDL_context_signal_mutex, &m_signal_cond, NULL);
582
662
DBUG_ASSERT(m_tickets.is_empty());
584
rwlock_destroy(&m_waiting_for_lock);
664
mysql_prlock_destroy(&m_waiting_for_lock);
585
665
mysql_mutex_destroy(&m_signal_lock);
586
666
mysql_cond_destroy(&m_signal_cond);
1314
1394
/* We can't get here if we allocated a new lock. */
1315
1395
DBUG_ASSERT(! lock->is_empty());
1316
rw_unlock(&lock->m_rwlock);
1396
mysql_prlock_unlock(&lock->m_rwlock);
1317
1397
MDL_ticket::destroy(ticket);
1354
1434
ticket->m_lock= mdl_request->ticket->m_lock;
1355
1435
mdl_request->ticket= ticket;
1357
rw_wrlock(&ticket->m_lock->m_rwlock);
1437
mysql_prlock_wrlock(&ticket->m_lock->m_rwlock);
1358
1438
ticket->m_lock->m_granted.add_ticket(ticket);
1359
rw_unlock(&ticket->m_lock->m_rwlock);
1439
mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
1361
1441
m_tickets.push_front(ticket);
1462
1542
if (ticket->is_upgradable_or_exclusive())
1463
1543
lock->notify_shared_locks(this);
1465
rw_unlock(&lock->m_rwlock);
1545
mysql_prlock_unlock(&lock->m_rwlock);
1467
1547
set_deadlock_weight(mdl_request->get_deadlock_weight());
1468
1548
will_wait_for(ticket);
1497
1577
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
1500
rw_wrlock(&lock->m_rwlock);
1580
mysql_prlock_wrlock(&lock->m_rwlock);
1503
1583
lock->m_waiting.remove_ticket(ticket);
1507
1587
(*lock->cached_object_release_hook)(lock->cached_object);
1508
1588
lock->cached_object= NULL;
1510
rw_unlock(&lock->m_rwlock);
1590
mysql_prlock_unlock(&lock->m_rwlock);
1512
1592
m_tickets.push_front(ticket);
1652
1732
is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket);
1654
1734
/* Merge the acquired and the original lock. @todo: move to a method. */
1655
rw_wrlock(&mdl_ticket->m_lock->m_rwlock);
1735
mysql_prlock_wrlock(&mdl_ticket->m_lock->m_rwlock);
1656
1736
if (is_new_ticket)
1657
1737
mdl_ticket->m_lock->m_granted.remove_ticket(mdl_xlock_request.ticket);
1772
1852
deadlock_ctx->victim= this;
1773
1853
else if (deadlock_ctx->victim->m_deadlock_weight >= m_deadlock_weight)
1775
rw_unlock(&deadlock_ctx->victim->m_waiting_for_lock);
1855
mysql_prlock_unlock(&deadlock_ctx->victim->m_waiting_for_lock);
1776
1856
deadlock_ctx->victim= this;
1779
rw_unlock(&m_waiting_for_lock);
1859
mysql_prlock_unlock(&m_waiting_for_lock);
1782
rw_unlock(&m_waiting_for_lock);
1862
mysql_prlock_unlock(&m_waiting_for_lock);
1805
1885
if (deadlock_ctx.victim != this)
1807
1887
deadlock_ctx.victim->awake(VICTIM_WAKE_UP);
1808
rw_unlock(&deadlock_ctx.victim->m_waiting_for_lock);
1888
mysql_prlock_unlock(&deadlock_ctx.victim->m_waiting_for_lock);
1810
1890
After adding new arc to waiting graph we found that it participates
1811
1891
in some loop (i.e. there is a deadlock). We decided to destroy this
1876
1956
if (lock->can_grant_lock(mdl_request->type, this))
1878
rw_unlock(&lock->m_rwlock);
1958
mysql_prlock_unlock(&lock->m_rwlock);
1882
1962
MDL_ticket *pending_ticket;
1883
1963
if (! (pending_ticket= MDL_ticket::create(this, mdl_request->type)))
1885
rw_unlock(&lock->m_rwlock);
1965
mysql_prlock_unlock(&lock->m_rwlock);
1891
1971
lock->m_waiting.add_ticket(pending_ticket);
1894
rw_unlock(&lock->m_rwlock);
1974
mysql_prlock_unlock(&lock->m_rwlock);
1896
1976
set_deadlock_weight(MDL_DEADLOCK_WEIGHT_DML);
1897
1977
will_wait_for(pending_ticket);
2042
2122
if (m_type != MDL_EXCLUSIVE)
2045
rw_wrlock(&m_lock->m_rwlock);
2125
mysql_prlock_wrlock(&m_lock->m_rwlock);
2047
2127
To update state of MDL_lock object correctly we need to temporarily
2048
2128
exclude ticket from the granted queue and then include it back.