~maria-captains/maria/mysql-6.0-backup

« back to all changes in this revision

Viewing changes to sql/mdl.cc

  • Committer: Thava Alagu
  • Date: 2010-03-11 19:18:17 UTC
  • mfrom: (3719.14.62 mysql-6.0-codebase)
  • Revision ID: thavamuni.alagu@sun.com-20100311191817-5nigmq884xo9fuut
Merge from mysql-6.0-codebase

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#include <hash.h>
20
20
#include <mysqld_error.h>
21
21
 
 
22
#ifdef HAVE_PSI_INTERFACE
 
23
static PSI_mutex_key key_MDL_map_mutex;
 
24
static PSI_mutex_key key_MDL_context_signal_mutex;
 
25
 
 
26
static PSI_mutex_info all_mdl_mutexes[]=
 
27
{
 
28
  { &key_MDL_map_mutex, "MDL_map::mutex", PSI_FLAG_GLOBAL},
 
29
  { &key_MDL_context_signal_mutex, "MDL_context::signal", 0}
 
30
};
 
31
 
 
32
static PSI_rwlock_key key_MDL_lock_rwlock;
 
33
static PSI_rwlock_key key_MDL_context_waiting_for_rwlock;
 
34
 
 
35
static PSI_rwlock_info all_mdl_rwlocks[]=
 
36
{
 
37
  { &key_MDL_lock_rwlock, "MDL_lock::rwlock", 0},
 
38
  { &key_MDL_context_waiting_for_rwlock, "MDL_context::waiting_for_lock", 0}
 
39
};
 
40
 
 
41
static PSI_cond_key key_MDL_context_signal_cond;
 
42
 
 
43
static PSI_cond_info all_mdl_conds[]=
 
44
{
 
45
  { &key_MDL_context_signal_cond, "MDL_context::signal", 0}
 
46
};
 
47
 
 
48
/**
 
49
  Initialise all the performance schema instrumentation points
 
50
  used by the MDL subsystem.
 
51
*/
 
52
static void init_mdl_psi_keys(void)
 
53
{
 
54
  const char *category= "sql";
 
55
  int count;
 
56
 
 
57
  if (PSI_server == NULL)
 
58
    return;
 
59
 
 
60
  count= array_elements(all_mdl_mutexes);
 
61
  PSI_server->register_mutex(category, all_mdl_mutexes, count);
 
62
 
 
63
  count= array_elements(all_mdl_rwlocks);
 
64
  PSI_server->register_rwlock(category, all_mdl_rwlocks, count);
 
65
 
 
66
  count= array_elements(all_mdl_conds);
 
67
  PSI_server->register_cond(category, all_mdl_conds, count);
 
68
}
 
69
#endif /* HAVE_PSI_INTERFACE */
22
70
 
23
71
void notify_shared_lock(THD *thd, MDL_ticket *conflicting_ticket);
24
72
 
148
196
  /**
149
197
    Read-write lock protecting this lock context.
150
198
 
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.
 
201
 
 
202
          For example, imagine that we have following waiters graph:
 
203
 
 
204
                       ctxA -> obj1 -> ctxB -> obj1 -|
 
205
                        ^                            |
 
206
                        |----------------------------|
 
207
 
 
208
          and both ctxA and ctxB start deadlock detection process:
 
209
 
 
210
            ctxA read-locks obj1             ctxB read-locks obj2
 
211
            ctxA goes deeper                 ctxB goes deeper
 
212
 
 
213
          Now ctxC comes in who wants to start waiting on obj1, also
 
214
          ctxD comes in who wants to start waiting on obj2.
 
215
 
 
216
            ctxC tries to write-lock obj1   ctxD tries to write-lock obj2
 
217
            ctxC is blocked                 ctxD is blocked
 
218
 
 
219
          Now ctxA and ctxB resume their search:
 
220
 
 
221
            ctxA tries to read-lock obj2    ctxB tries to read-lock obj1
 
222
 
 
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.
153
228
  */
154
 
  rw_lock_t m_rwlock;
 
229
  mysql_prlock_t m_rwlock;
155
230
 
156
231
  bool is_empty() const
157
232
  {
213
288
    m_ref_release(0),
214
289
    m_is_destroyed(FALSE)
215
290
  {
216
 
    my_rwlock_init(&m_rwlock, NULL);
 
291
    mysql_prlock_init(key_MDL_lock_rwlock, &m_rwlock);
217
292
  }
218
293
 
219
294
  virtual ~MDL_lock()
220
295
  {
221
 
    rwlock_destroy(&m_rwlock);
 
296
    mysql_prlock_destroy(&m_rwlock);
222
297
  }
223
298
  inline static void destroy(MDL_lock *lock);
224
299
public:
341
416
{
342
417
  DBUG_ASSERT(! mdl_initialized);
343
418
  mdl_initialized= TRUE;
 
419
 
 
420
#ifdef HAVE_PSI_INTERFACE
 
421
  init_mdl_psi_keys();
 
422
#endif
 
423
 
344
424
  mdl_locks.init();
345
425
}
346
426
 
366
446
 
367
447
void MDL_map::init()
368
448
{
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);
372
452
}
480
560
  lock->m_ref_usage++;
481
561
  mysql_mutex_unlock(&m_mutex);
482
562
 
483
 
  rw_wrlock(&lock->m_rwlock);
 
563
  mysql_prlock_wrlock(&lock->m_rwlock);
484
564
  lock->m_ref_release++;
485
565
  if (unlikely(lock->m_is_destroyed))
486
566
  {
495
575
    */
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);
501
581
    return TRUE;
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)
561
641
{
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);
565
645
}
566
646
 
567
647
 
581
661
{
582
662
  DBUG_ASSERT(m_tickets.is_empty());
583
663
 
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);
587
667
}
1076
1156
 
1077
1157
void MDL_lock::remove_ticket(Ticket_list MDL_lock::*list, MDL_ticket *ticket)
1078
1158
{
1079
 
  rw_wrlock(&m_rwlock);
 
1159
  mysql_prlock_wrlock(&m_rwlock);
1080
1160
  (this->*list).remove_ticket(ticket);
1081
1161
  if (is_empty())
1082
1162
    mdl_locks.remove(this);
1087
1167
      which now might be able to do it. Wake them up!
1088
1168
    */
1089
1169
    wake_up_waiters();
1090
 
    rw_unlock(&m_rwlock);
 
1170
    mysql_prlock_unlock(&m_rwlock);
1091
1171
  }
1092
1172
}
1093
1173
 
1107
1187
 
1108
1188
  mysql_mutex_assert_not_owner(&LOCK_open);
1109
1189
 
1110
 
  rw_rdlock(&m_rwlock);
 
1190
  mysql_prlock_rdlock(&m_rwlock);
1111
1191
  result= (m_waiting.bitmap() & incompatible_granted_types_bitmap()[type]);
1112
 
  rw_unlock(&m_rwlock);
 
1192
  mysql_prlock_unlock(&m_rwlock);
1113
1193
  return result;
1114
1194
}
1115
1195
 
1303
1383
  {
1304
1384
    ticket->m_lock= lock;
1305
1385
    lock->m_granted.add_ticket(ticket);
1306
 
    rw_unlock(&lock->m_rwlock);
 
1386
    mysql_prlock_unlock(&lock->m_rwlock);
1307
1387
 
1308
1388
    m_tickets.push_front(ticket);
1309
1389
 
1313
1393
  {
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);
1318
1398
  }
1319
1399
 
1354
1434
  ticket->m_lock= mdl_request->ticket->m_lock;
1355
1435
  mdl_request->ticket= ticket;
1356
1436
 
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);
1360
1440
 
1361
1441
  m_tickets.push_front(ticket);
1362
1442
 
1462
1542
    if (ticket->is_upgradable_or_exclusive())
1463
1543
      lock->notify_shared_locks(this);
1464
1544
 
1465
 
    rw_unlock(&lock->m_rwlock);
 
1545
    mysql_prlock_unlock(&lock->m_rwlock);
1466
1546
 
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));
1498
1578
      return TRUE;
1499
1579
    }
1500
 
    rw_wrlock(&lock->m_rwlock);
 
1580
    mysql_prlock_wrlock(&lock->m_rwlock);
1501
1581
  }
1502
1582
 
1503
1583
  lock->m_waiting.remove_ticket(ticket);
1507
1587
    (*lock->cached_object_release_hook)(lock->cached_object);
1508
1588
  lock->cached_object= NULL;
1509
1589
 
1510
 
  rw_unlock(&lock->m_rwlock);
 
1590
  mysql_prlock_unlock(&lock->m_rwlock);
1511
1591
 
1512
1592
  m_tickets.push_front(ticket);
1513
1593
 
1652
1732
  is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket);
1653
1733
 
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);
1658
1738
  /*
1664
1744
  mdl_ticket->m_type= MDL_EXCLUSIVE;
1665
1745
  mdl_ticket->m_lock->m_granted.add_ticket(mdl_ticket);
1666
1746
 
1667
 
  rw_unlock(&mdl_ticket->m_lock->m_rwlock);
 
1747
  mysql_prlock_unlock(&mdl_ticket->m_lock->m_rwlock);
1668
1748
 
1669
1749
  if (is_new_ticket)
1670
1750
  {
1682
1762
  MDL_ticket *ticket;
1683
1763
  bool result= FALSE;
1684
1764
 
1685
 
  rw_rdlock(&m_rwlock);
 
1765
  mysql_prlock_rdlock(&m_rwlock);
1686
1766
 
1687
1767
  Ticket_iterator granted_it(m_granted);
1688
1768
  Ticket_iterator waiting_it(m_waiting);
1734
1814
  }
1735
1815
 
1736
1816
end:
1737
 
  rw_unlock(&m_rwlock);
 
1817
  mysql_prlock_unlock(&m_rwlock);
1738
1818
  return result;
1739
1819
}
1740
1820
 
1743
1823
{
1744
1824
  bool result= FALSE;
1745
1825
 
1746
 
  rw_rdlock(&m_waiting_for_lock);
 
1826
  mysql_prlock_rdlock(&m_waiting_for_lock);
1747
1827
 
1748
1828
  if (m_waiting_for)
1749
1829
  {
1772
1852
      deadlock_ctx->victim= this;
1773
1853
    else if (deadlock_ctx->victim->m_deadlock_weight >= m_deadlock_weight)
1774
1854
    {
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;
1777
1857
    }
1778
1858
    else
1779
 
      rw_unlock(&m_waiting_for_lock);
 
1859
      mysql_prlock_unlock(&m_waiting_for_lock);
1780
1860
  }
1781
1861
  else
1782
 
    rw_unlock(&m_waiting_for_lock);
 
1862
    mysql_prlock_unlock(&m_waiting_for_lock);
1783
1863
 
1784
1864
  return result;
1785
1865
}
1805
1885
    if (deadlock_ctx.victim != this)
1806
1886
    {
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);
1809
1889
      /*
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
1818
1898
    else
1819
1899
    {
1820
1900
      DBUG_ASSERT(&deadlock_ctx.victim->m_waiting_for_lock == &m_waiting_for_lock);
1821
 
      rw_unlock(&deadlock_ctx.victim->m_waiting_for_lock);
 
1901
      mysql_prlock_unlock(&deadlock_ctx.victim->m_waiting_for_lock);
1822
1902
      return TRUE;
1823
1903
    }
1824
1904
  }
1875
1955
 
1876
1956
    if (lock->can_grant_lock(mdl_request->type, this))
1877
1957
    {
1878
 
      rw_unlock(&lock->m_rwlock);
 
1958
      mysql_prlock_unlock(&lock->m_rwlock);
1879
1959
      return FALSE;
1880
1960
    }
1881
1961
 
1882
1962
    MDL_ticket *pending_ticket;
1883
1963
    if (! (pending_ticket= MDL_ticket::create(this, mdl_request->type)))
1884
1964
    {
1885
 
      rw_unlock(&lock->m_rwlock);
 
1965
      mysql_prlock_unlock(&lock->m_rwlock);
1886
1966
      return TRUE;
1887
1967
    }
1888
1968
 
1891
1971
    lock->m_waiting.add_ticket(pending_ticket);
1892
1972
 
1893
1973
    wait_reset();
1894
 
    rw_unlock(&lock->m_rwlock);
 
1974
    mysql_prlock_unlock(&lock->m_rwlock);
1895
1975
 
1896
1976
    set_deadlock_weight(MDL_DEADLOCK_WEIGHT_DML);
1897
1977
    will_wait_for(pending_ticket);
2042
2122
  if (m_type != MDL_EXCLUSIVE)
2043
2123
    return;
2044
2124
 
2045
 
  rw_wrlock(&m_lock->m_rwlock);
 
2125
  mysql_prlock_wrlock(&m_lock->m_rwlock);
2046
2126
  /*
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.
2051
2131
  m_type= type;
2052
2132
  m_lock->m_granted.add_ticket(this);
2053
2133
  m_lock->wake_up_waiters();
2054
 
  rw_unlock(&m_lock->m_rwlock);
 
2134
  mysql_prlock_unlock(&m_lock->m_rwlock);
2055
2135
}
2056
2136
 
2057
2137