summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorJimmy Yang <jimmy.yang@oracle.com>2010-08-04 03:37:44 -0700
committerJimmy Yang <jimmy.yang@oracle.com>2010-08-04 03:37:44 -0700
commitad90d1942ec916fe45a2bfa35a78c36c8920b1d9 (patch)
tree9e629248e41afd4bcd4880a8db71c03de0aca686 /storage
parent04970a2ff1d0019e256f12626c85266c3a0ebf35 (diff)
downloadmariadb-git-ad90d1942ec916fe45a2bfa35a78c36c8920b1d9.tar.gz
Fix bug #54678, InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
rb://399 approved by Sunny Bains
Diffstat (limited to 'storage')
-rw-r--r--storage/innodb_plugin/ChangeLog5
-rw-r--r--storage/innodb_plugin/include/dict0dict.h16
-rw-r--r--storage/innodb_plugin/include/dict0dict.ic42
-rw-r--r--storage/innodb_plugin/row/row0mysql.c14
4 files changed, 77 insertions, 0 deletions
diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog
index 56729852a62..ce625a93871 100644
--- a/storage/innodb_plugin/ChangeLog
+++ b/storage/innodb_plugin/ChangeLog
@@ -1,5 +1,10 @@
2010-08-03 The InnoDB Team
+ * include/dict0dict.h, include/dict0dict.ic, row/row0mysql.c:
+ Fix bug #54678, InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
+
+2010-08-03 The InnoDB Team
+
* dict/dict0load.c, handler/ha_innodb.cc, include/db0err.h,
include/dict0load.h, include/dict0mem.h, include/que0que.h,
row/row0merge.c, row/row0mysql.c:
diff --git a/storage/innodb_plugin/include/dict0dict.h b/storage/innodb_plugin/include/dict0dict.h
index 3a1bee4cd89..5ffa59538c8 100644
--- a/storage/innodb_plugin/include/dict0dict.h
+++ b/storage/innodb_plugin/include/dict0dict.h
@@ -680,6 +680,22 @@ ulint
dict_table_zip_size(
/*================*/
const dict_table_t* table); /*!< in: table */
+/*********************************************************************//**
+Obtain exclusive locks on all index trees of the table. This is to prevent
+accessing index trees while InnoDB is updating internal metadata for
+operations such as truncate tables. */
+UNIV_INLINE
+void
+dict_table_x_lock_indexes(
+/*======================*/
+ dict_table_t* table); /*!< in: table */
+/*********************************************************************//**
+Release the exclusive locks on all index tree. */
+UNIV_INLINE
+void
+dict_table_x_unlock_indexes(
+/*========================*/
+ dict_table_t* table); /*!< in: table */
/********************************************************************//**
Checks if a column is in the ordering columns of the clustered index of a
table. Column prefixes are treated like whole columns.
diff --git a/storage/innodb_plugin/include/dict0dict.ic b/storage/innodb_plugin/include/dict0dict.ic
index 46e78df8272..1704e9c2d71 100644
--- a/storage/innodb_plugin/include/dict0dict.ic
+++ b/storage/innodb_plugin/include/dict0dict.ic
@@ -452,6 +452,48 @@ dict_table_zip_size(
return(dict_table_flags_to_zip_size(table->flags));
}
+/*********************************************************************//**
+Obtain exclusive locks on all index trees of the table. This is to prevent
+accessing index trees while InnoDB is updating internal metadata for
+operations such as truncate tables. */
+UNIV_INLINE
+void
+dict_table_x_lock_indexes(
+/*======================*/
+ dict_table_t* table) /*!< in: table */
+{
+ dict_index_t* index;
+
+ ut_a(table);
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ /* Loop through each index of the table and lock them */
+ for (index = dict_table_get_first_index(table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+ rw_lock_x_lock(dict_index_get_lock(index));
+ }
+}
+
+/*********************************************************************//**
+Release the exclusive locks on all index tree. */
+UNIV_INLINE
+void
+dict_table_x_unlock_indexes(
+/*========================*/
+ dict_table_t* table) /*!< in: table */
+{
+ dict_index_t* index;
+
+ ut_a(table);
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ for (index = dict_table_get_first_index(table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+ rw_lock_x_unlock(dict_index_get_lock(index));
+ }
+}
/********************************************************************//**
Gets the number of fields in the internal representation of an index,
including fields added by the dictionary system.
diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c
index a582de3e583..9d7cb976caf 100644
--- a/storage/innodb_plugin/row/row0mysql.c
+++ b/storage/innodb_plugin/row/row0mysql.c
@@ -2766,6 +2766,15 @@ row_truncate_table_for_mysql(
trx->table_id = table->id;
+ /* Lock all index trees for this table, as we will
+ truncate the table/index and possibly change their metadata.
+ All DML/DDL are blocked by table level lock, with
+ a few exceptions such as queries into information schema
+ about the table, MySQL could try to access index stats
+ for this kind of query, we need to use index locks to
+ sync up */
+ dict_table_x_lock_indexes(table);
+
if (table->space && !table->dir_path_of_temp_table) {
/* Discard and create the single-table tablespace. */
ulint space = table->space;
@@ -2782,6 +2791,7 @@ row_truncate_table_for_mysql(
|| fil_create_new_single_table_tablespace(
space, table->name, FALSE, flags,
FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
+ dict_table_x_unlock_indexes(table);
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: TRUNCATE TABLE %s failed to"
@@ -2885,6 +2895,10 @@ next_rec:
mem_heap_free(heap);
+ /* Done with index truncation, release index tree locks,
+ subsequent work relates to table level metadata change */
+ dict_table_x_unlock_indexes(table);
+
dict_hdr_get_new_id(&new_id, NULL, NULL);
info = pars_info_create();