Commit dd11eadc authored by unknown's avatar unknown

ha_innodb.cc:

  Fix a possible hang at the adaptive hash index latch if MySQL does query estimations also in the middle of a SELECT statement processing


sql/ha_innodb.cc:
  Fix a possible hang at the adaptive hash index latch if MySQL does query estimations also in the middle of a SELECT statement processing
parent fb016353
...@@ -2994,6 +2994,7 @@ ha_innobase::create( ...@@ -2994,6 +2994,7 @@ ha_innobase::create(
{ {
int error; int error;
dict_table_t* innobase_table; dict_table_t* innobase_table;
trx_t* parent_trx;
trx_t* trx; trx_t* trx;
int primary_key_no; int primary_key_no;
uint i; uint i;
...@@ -3005,6 +3006,16 @@ ha_innobase::create( ...@@ -3005,6 +3006,16 @@ ha_innobase::create(
DBUG_ASSERT(thd != NULL); DBUG_ASSERT(thd != NULL);
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(parent_trx);
trx = trx_allocate_for_mysql(); trx = trx_allocate_for_mysql();
if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
...@@ -3165,11 +3176,22 @@ ha_innobase::delete_table( ...@@ -3165,11 +3176,22 @@ ha_innobase::delete_table(
{ {
ulint name_len; ulint name_len;
int error; int error;
trx_t* parent_trx;
trx_t* trx; trx_t* trx;
char norm_name[1000]; char norm_name[1000];
DBUG_ENTER("ha_innobase::delete_table"); DBUG_ENTER("ha_innobase::delete_table");
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(parent_trx);
if (lower_case_table_names) { if (lower_case_table_names) {
srv_lower_case_table_names = TRUE; srv_lower_case_table_names = TRUE;
} else { } else {
...@@ -3224,11 +3246,22 @@ innobase_drop_database( ...@@ -3224,11 +3246,22 @@ innobase_drop_database(
the database name is 'test' */ the database name is 'test' */
{ {
ulint len = 0; ulint len = 0;
trx_t* parent_trx;
trx_t* trx; trx_t* trx;
char* ptr; char* ptr;
int error; int error;
char namebuf[10000]; char namebuf[10000];
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(parent_trx);
ptr = strend(path) - 2; ptr = strend(path) - 2;
while (ptr >= path && *ptr != '\\' && *ptr != '/') { while (ptr >= path && *ptr != '\\' && *ptr != '/') {
...@@ -3280,12 +3313,23 @@ ha_innobase::rename_table( ...@@ -3280,12 +3313,23 @@ ha_innobase::rename_table(
ulint name_len1; ulint name_len1;
ulint name_len2; ulint name_len2;
int error; int error;
trx_t* parent_trx;
trx_t* trx; trx_t* trx;
char norm_from[1000]; char norm_from[1000];
char norm_to[1000]; char norm_to[1000];
DBUG_ENTER("ha_innobase::rename_table"); DBUG_ENTER("ha_innobase::rename_table");
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(parent_trx);
if (lower_case_table_names) { if (lower_case_table_names) {
srv_lower_case_table_names = TRUE; srv_lower_case_table_names = TRUE;
} else { } else {
...@@ -3332,8 +3376,8 @@ Estimates the number of index records in a range. */ ...@@ -3332,8 +3376,8 @@ Estimates the number of index records in a range. */
ha_rows ha_rows
ha_innobase::records_in_range( ha_innobase::records_in_range(
/*==========================*/ /*==========================*/
/* out: estimated number of rows, /* out: estimated number of
currently 32-bit int or uint */ rows */
int keynr, /* in: index number */ int keynr, /* in: index number */
const mysql_byte* start_key, /* in: start key value of the const mysql_byte* start_key, /* in: start key value of the
range, may also be empty */ range, may also be empty */
...@@ -3364,9 +3408,16 @@ ha_innobase::records_in_range( ...@@ -3364,9 +3408,16 @@ ha_innobase::records_in_range(
DBUG_ENTER("records_in_range"); DBUG_ENTER("records_in_range");
/* Warning: since it is not sure that MySQL calls external_lock /* We do not know if MySQL can call this function before calling
before calling this function, the trx field in prebuilt can be external_lock(). To be safe, update the thd of the current table
obsolete! */ handle. */
update_thd(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(prebuilt->trx);
active_index = keynr; active_index = keynr;
...@@ -3420,12 +3471,19 @@ ha_innobase::estimate_number_of_rows(void) ...@@ -3420,12 +3471,19 @@ ha_innobase::estimate_number_of_rows(void)
ulonglong estimate; ulonglong estimate;
ulonglong local_data_file_length; ulonglong local_data_file_length;
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
DBUG_ENTER("info"); DBUG_ENTER("info");
/* We do not know if MySQL can call this function before calling
external_lock(). To be safe, update the thd of the current table
handle. */
update_thd(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(prebuilt->trx);
index = dict_table_get_first_index_noninline(prebuilt->table); index = dict_table_get_first_index_noninline(prebuilt->table);
local_data_file_length = ((ulonglong) index->stat_n_leaf_pages) local_data_file_length = ((ulonglong) index->stat_n_leaf_pages)
...@@ -3489,9 +3547,16 @@ ha_innobase::info( ...@@ -3489,9 +3547,16 @@ ha_innobase::info(
return; return;
} }
/* Warning: since it is not sure that MySQL calls external_lock /* We do not know if MySQL can call this function before calling
before calling this function, the trx field in prebuilt can be external_lock(). To be safe, update the thd of the current table
obsolete! */ handle. */
update_thd(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(prebuilt->trx);
ib_table = prebuilt->table; ib_table = prebuilt->table;
...@@ -3559,12 +3624,6 @@ ha_innobase::info( ...@@ -3559,12 +3624,6 @@ ha_innobase::info(
} }
} }
/* The trx struct in InnoDB contains a pthread mutex embedded:
in the debug version of MySQL that it replaced by a 'safe mutex'
which is of a different size. We have to use a function to access
trx fields. Otherwise trx->error_info will be a random
pointer and cause a seg fault. */
if (flag & HA_STATUS_ERRKEY) { if (flag & HA_STATUS_ERRKEY) {
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N); ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
...@@ -3630,9 +3689,16 @@ ha_innobase::update_table_comment( ...@@ -3630,9 +3689,16 @@ ha_innobase::update_table_comment(
char* str = my_malloc(length + 16500, MYF(0)); char* str = my_malloc(length + 16500, MYF(0));
char* pos; char* pos;
/* Warning: since it is not sure that MySQL calls external_lock /* We do not know if MySQL can call this function before calling
before calling this function, the trx field in prebuilt can be external_lock(). To be safe, update the thd of the current table
obsolete! */ handle. */
update_thd(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(prebuilt->trx);
if (!str) { if (!str) {
return((char*)comment); return((char*)comment);
...@@ -3674,6 +3740,17 @@ ha_innobase::get_foreign_key_create_info(void) ...@@ -3674,6 +3740,17 @@ ha_innobase::get_foreign_key_create_info(void)
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
char* str; char* str;
/* We do not know if MySQL can call this function before calling
external_lock(). To be safe, update the thd of the current table
handle. */
update_thd(current_thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(prebuilt->trx);
if (prebuilt == NULL) { if (prebuilt == NULL) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: cannot get create info for foreign keys\n"); "InnoDB: Error: cannot get create info for foreign keys\n");
...@@ -3752,9 +3829,10 @@ ha_innobase::reset(void) ...@@ -3752,9 +3829,10 @@ ha_innobase::reset(void)
} }
/********************************************************************** /**********************************************************************
When we create a temporary table inside MySQL LOCK TABLES, MySQL will Inside LOCK TABLES MySQL will not call external_lock() between SQL
not call external_lock for the temporary table when it uses it. Instead, statements. It will call this function at the start of each SQL statement.
it will call this function. */ Note also a spacial case: if a temporary table is created inside LOCK
TABLES, MySQL has not called external_lock() at all on that table. */
int int
ha_innobase::start_stmt( ha_innobase::start_stmt(
...@@ -3892,8 +3970,8 @@ ha_innobase::external_lock( ...@@ -3892,8 +3970,8 @@ ha_innobase::external_lock(
trx->mysql_n_tables_locked = 0; trx->mysql_n_tables_locked = 0;
/* Here we release the search latch, auto_inc_lock, /* Here we release the search latch and InnoDB
and InnoDB thread FIFO ticket if they were reserved. */ thread FIFO ticket if they were reserved. */
innobase_release_stat_resources(trx); innobase_release_stat_resources(trx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment