mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
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
This commit is contained in:
130
sql/ha_innodb.cc
130
sql/ha_innodb.cc
@ -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(
|
|||||||
|
|
||||||
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(
|
|||||||
{
|
{
|
||||||
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(
|
|||||||
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(
|
|||||||
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. */
|
|||||||
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(
|
|||||||
|
|
||||||
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)
|
|||||||
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(
|
|||||||
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(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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(
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
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(
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user