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(
{
int error;
dict_table_t* innobase_table;
trx_t* parent_trx;
trx_t* trx;
int primary_key_no;
uint i;
......@@ -3005,6 +3006,16 @@ ha_innobase::create(
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();
if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
......@@ -3165,11 +3176,22 @@ ha_innobase::delete_table(
{
ulint name_len;
int error;
trx_t* parent_trx;
trx_t* trx;
char norm_name[1000];
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) {
srv_lower_case_table_names = TRUE;
} else {
......@@ -3224,11 +3246,22 @@ innobase_drop_database(
the database name is 'test' */
{
ulint len = 0;
trx_t* parent_trx;
trx_t* trx;
char* ptr;
int error;
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;
while (ptr >= path && *ptr != '\\' && *ptr != '/') {
......@@ -3280,12 +3313,23 @@ ha_innobase::rename_table(
ulint name_len1;
ulint name_len2;
int error;
trx_t* parent_trx;
trx_t* trx;
char norm_from[1000];
char norm_to[1000];
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) {
srv_lower_case_table_names = TRUE;
} else {
......@@ -3332,8 +3376,8 @@ Estimates the number of index records in a range. */
ha_rows
ha_innobase::records_in_range(
/*==========================*/
/* out: estimated number of rows,
currently 32-bit int or uint */
/* out: estimated number of
rows */
int keynr, /* in: index number */
const mysql_byte* start_key, /* in: start key value of the
range, may also be empty */
......@@ -3364,9 +3408,16 @@ ha_innobase::records_in_range(
DBUG_ENTER("records_in_range");
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
/* 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);
active_index = keynr;
......@@ -3420,12 +3471,19 @@ ha_innobase::estimate_number_of_rows(void)
ulonglong estimate;
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");
/* 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);
local_data_file_length = ((ulonglong) index->stat_n_leaf_pages)
......@@ -3489,9 +3547,16 @@ ha_innobase::info(
return;
}
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
/* 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);
ib_table = prebuilt->table;
......@@ -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) {
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
......@@ -3630,9 +3689,16 @@ ha_innobase::update_table_comment(
char* str = my_malloc(length + 16500, MYF(0));
char* pos;
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
/* 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 (!str) {
return((char*)comment);
......@@ -3673,6 +3739,17 @@ ha_innobase::get_foreign_key_create_info(void)
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
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) {
fprintf(stderr,
......@@ -3752,9 +3829,10 @@ ha_innobase::reset(void)
}
/**********************************************************************
When we create a temporary table inside MySQL LOCK TABLES, MySQL will
not call external_lock for the temporary table when it uses it. Instead,
it will call this function. */
Inside LOCK TABLES MySQL will not call external_lock() between SQL
statements. It will call this function at the start of each SQL statement.
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
ha_innobase::start_stmt(
......@@ -3892,8 +3970,8 @@ ha_innobase::external_lock(
trx->mysql_n_tables_locked = 0;
/* Here we release the search latch, auto_inc_lock,
and InnoDB thread FIFO ticket if they were reserved. */
/* Here we release the search latch and InnoDB
thread FIFO ticket if they were reserved. */
innobase_release_stat_resources(trx);
......@@ -4209,4 +4287,4 @@ ha_innobase::get_auto_increment()
}
#endif /* HAVE_INNOBASE_DB */
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