Merge lp:~sergei.glushchenko/percona-server/ps51-bug903617 into lp:percona-server/5.1

Proposed by Sergei Glushchenko
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 429
Proposed branch: lp:~sergei.glushchenko/percona-server/ps51-bug903617
Merge into: lp:percona-server/5.1
Diff against target: 76 lines (+37/-2)
1 file modified
Percona-Server/storage/innodb_plugin/dict/dict0dict.c (+37/-2)
To merge this branch: bzr merge lp:~sergei.glushchenko/percona-server/ps51-bug903617
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+94741@code.launchpad.net

Description of the change

Bug903617
Deadlock or crash on concurrent
  TRUNCATE TABLE testdb.t
and
  SELECT * FROM information_schema.tables
           WHERE table_schema="testdb" AND table_name="t"
dict_stats_latches array of RW-locks is used for locking dict
statisctics. Latch to lock is picked by table->id. TRUNCATE TABLE changes
table->id without locking any latches.
Solution is to lock the latch in exclusive mode before changing
table->id. The fact that table->id could change also taken to account
in the latch locking algorithm.

http://jenkins.percona.com/view/Percona%20Server%205.1/job/percona-server-5.1-param/275/

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Sergei,

The patch looks good to me, but please add short comments before the for loops and the call to dict_table_stats_lock() explaining why it's being done, as it may not be obvious without knowing the bug context. Please also add the upstream bug number to commit message when you have it.

review: Needs Fixing
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

> Sergei,
>
> The patch looks good to me, but please add short comments before the for loops
> and the call to dict_table_stats_lock() explaining why it's being done, as it
> may not be obvious without knowing the bug context. Please also add the
> upstream bug number to commit message when you have it.

DONE.

Revision history for this message
Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Percona-Server/storage/innodb_plugin/dict/dict0dict.c'
2--- Percona-Server/storage/innodb_plugin/dict/dict0dict.c 2011-11-24 16:33:30 +0000
3+++ Percona-Server/storage/innodb_plugin/dict/dict0dict.c 2012-02-28 03:27:27 +0000
4@@ -270,15 +270,39 @@
5 ulint latch_mode) /*!< in: RW_S_LATCH or
6 RW_X_LATCH */
7 {
8+ rw_lock_t *want, *got;
9+
10 ut_ad(table != NULL);
11 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
12
13 switch (latch_mode) {
14 case RW_S_LATCH:
15- rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
16+ /* Lock one of dict_table_stats_latches in S-mode.
17+ Latch is picked using table->id. table->id might be
18+ changed while we are waiting for lock to be grabbed */
19+ for (;;) {
20+ want= GET_TABLE_STATS_LATCH(table);
21+ rw_lock_s_lock(want);
22+ got= GET_TABLE_STATS_LATCH(table);
23+ if (want == got) {
24+ break;
25+ }
26+ rw_lock_s_unlock(want);
27+ }
28 break;
29 case RW_X_LATCH:
30- rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
31+ /* Lock one of dict_table_stats_latches in X-mode.
32+ Latch is picked using table->id. table->id might be
33+ changed while we are waiting for lock to be grabbed */
34+ for (;;) {
35+ want= GET_TABLE_STATS_LATCH(table);
36+ rw_lock_x_lock(want);
37+ got= GET_TABLE_STATS_LATCH(table);
38+ if (want == got) {
39+ break;
40+ }
41+ rw_lock_x_unlock(want);
42+ }
43 break;
44 case RW_NO_LATCH:
45 /* fall through */
46@@ -1164,12 +1188,21 @@
47 dict_table_t* table, /*!< in/out: table object already in cache */
48 dulint new_id) /*!< in: new id to set */
49 {
50+ dict_table_t table_tmp;
51+
52 ut_ad(table);
53 ut_ad(mutex_own(&(dict_sys->mutex)));
54 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
55
56 /* Remove the table from the hash table of id's */
57
58+ /* Lock is needed to prevent dict_table_stats_latches from
59+ being leaked. dict_table_stats_lock picks one latch using
60+ table->id. We are changing table->id below. That is why
61+ we also should remember the old value to unlock table */
62+ dict_table_stats_lock(table, RW_X_LATCH);
63+ table_tmp= *table;
64+
65 HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
66 ut_fold_dulint(table->id), table);
67 table->id = new_id;
68@@ -1177,6 +1210,8 @@
69 /* Add the table back to the hash table */
70 HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
71 ut_fold_dulint(table->id), table);
72+
73+ dict_table_stats_unlock(&table_tmp, RW_X_LATCH);
74 }
75
76 /**********************************************************************//**

Subscribers

People subscribed via source and target branches