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
=== modified file 'Percona-Server/storage/innodb_plugin/dict/dict0dict.c'
--- Percona-Server/storage/innodb_plugin/dict/dict0dict.c 2011-11-24 16:33:30 +0000
+++ Percona-Server/storage/innodb_plugin/dict/dict0dict.c 2012-02-28 03:27:27 +0000
@@ -270,15 +270,39 @@
270 ulint latch_mode) /*!< in: RW_S_LATCH or270 ulint latch_mode) /*!< in: RW_S_LATCH or
271 RW_X_LATCH */271 RW_X_LATCH */
272{272{
273 rw_lock_t *want, *got;
274
273 ut_ad(table != NULL);275 ut_ad(table != NULL);
274 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);276 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
275277
276 switch (latch_mode) {278 switch (latch_mode) {
277 case RW_S_LATCH:279 case RW_S_LATCH:
278 rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));280 /* Lock one of dict_table_stats_latches in S-mode.
281 Latch is picked using table->id. table->id might be
282 changed while we are waiting for lock to be grabbed */
283 for (;;) {
284 want= GET_TABLE_STATS_LATCH(table);
285 rw_lock_s_lock(want);
286 got= GET_TABLE_STATS_LATCH(table);
287 if (want == got) {
288 break;
289 }
290 rw_lock_s_unlock(want);
291 }
279 break;292 break;
280 case RW_X_LATCH:293 case RW_X_LATCH:
281 rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));294 /* Lock one of dict_table_stats_latches in X-mode.
295 Latch is picked using table->id. table->id might be
296 changed while we are waiting for lock to be grabbed */
297 for (;;) {
298 want= GET_TABLE_STATS_LATCH(table);
299 rw_lock_x_lock(want);
300 got= GET_TABLE_STATS_LATCH(table);
301 if (want == got) {
302 break;
303 }
304 rw_lock_x_unlock(want);
305 }
282 break;306 break;
283 case RW_NO_LATCH:307 case RW_NO_LATCH:
284 /* fall through */308 /* fall through */
@@ -1164,12 +1188,21 @@
1164 dict_table_t* table, /*!< in/out: table object already in cache */1188 dict_table_t* table, /*!< in/out: table object already in cache */
1165 dulint new_id) /*!< in: new id to set */1189 dulint new_id) /*!< in: new id to set */
1166{1190{
1191 dict_table_t table_tmp;
1192
1167 ut_ad(table);1193 ut_ad(table);
1168 ut_ad(mutex_own(&(dict_sys->mutex)));1194 ut_ad(mutex_own(&(dict_sys->mutex)));
1169 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);1195 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
11701196
1171 /* Remove the table from the hash table of id's */1197 /* Remove the table from the hash table of id's */
11721198
1199 /* Lock is needed to prevent dict_table_stats_latches from
1200 being leaked. dict_table_stats_lock picks one latch using
1201 table->id. We are changing table->id below. That is why
1202 we also should remember the old value to unlock table */
1203 dict_table_stats_lock(table, RW_X_LATCH);
1204 table_tmp= *table;
1205
1173 HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,1206 HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1174 ut_fold_dulint(table->id), table);1207 ut_fold_dulint(table->id), table);
1175 table->id = new_id;1208 table->id = new_id;
@@ -1177,6 +1210,8 @@
1177 /* Add the table back to the hash table */1210 /* Add the table back to the hash table */
1178 HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,1211 HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1179 ut_fold_dulint(table->id), table);1212 ut_fold_dulint(table->id), table);
1213
1214 dict_table_stats_unlock(&table_tmp, RW_X_LATCH);
1180}1215}
11811216
1182/**********************************************************************//**1217/**********************************************************************//**

Subscribers

People subscribed via source and target branches