mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
Bug #27326796 - MYSQL CRASH WITH INNODB ASSERTION FAILURE IN FILE PARS0PARS.CC
Problem: As part of bug #24938374 fix, dict_operation_lock was not taken by fts_optimize_thread while syncing fts cache. Due to this change, alter query is able to update SYS_TABLE rows simultaneously. Now when fts_optimizer_thread goes open index table, It doesn't open index table if the record corresponding to that table is set to REC_INFO_DELETED_FLAG in SYS_TABLES and hits an assert. Fix: If fts sync is already in progress, Alter query would wait for sync to complete before renaming table. RB: #19604 Reviewed by : Jimmy.Yang@oracle.com
This commit is contained in:
parent
91181b225c
commit
29ddc6e9e3
4 changed files with 116 additions and 72 deletions
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2016, 2018, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -869,37 +869,28 @@ fts_drop_index(
|
|||
|
||||
err = fts_drop_index_tables(trx, index);
|
||||
|
||||
for(;;) {
|
||||
bool retry = false;
|
||||
if (index->index_fts_syncing) {
|
||||
retry = true;
|
||||
}
|
||||
if (!retry){
|
||||
fts_free(table);
|
||||
break;
|
||||
}
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
|
||||
fts_free(table);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
bool retry = false;
|
||||
if (index->index_fts_syncing) {
|
||||
retry = true;
|
||||
}
|
||||
if (!retry){
|
||||
current_doc_id = table->fts->cache->next_doc_id;
|
||||
first_doc_id = table->fts->cache->first_doc_id;
|
||||
fts_cache_clear(table->fts->cache);
|
||||
fts_cache_destroy(table->fts->cache);
|
||||
table->fts->cache = fts_cache_create(table);
|
||||
table->fts->cache->next_doc_id = current_doc_id;
|
||||
table->fts->cache->first_doc_id = first_doc_id;
|
||||
break;
|
||||
}
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
|
||||
current_doc_id = table->fts->cache->next_doc_id;
|
||||
first_doc_id = table->fts->cache->first_doc_id;
|
||||
fts_cache_clear(table->fts->cache);
|
||||
fts_cache_destroy(table->fts->cache);
|
||||
table->fts->cache = fts_cache_create(table);
|
||||
table->fts->cache->next_doc_id = current_doc_id;
|
||||
table->fts->cache->first_doc_id = first_doc_id;
|
||||
} else {
|
||||
fts_cache_t* cache = table->fts->cache;
|
||||
fts_index_cache_t* index_cache;
|
||||
|
@ -909,18 +900,14 @@ fts_drop_index(
|
|||
index_cache = fts_find_index_cache(cache, index);
|
||||
|
||||
if (index_cache != NULL) {
|
||||
for(;;) {
|
||||
bool retry = false;
|
||||
if (index->index_fts_syncing) {
|
||||
retry = true;
|
||||
}
|
||||
if (!retry && index_cache->words) {
|
||||
fts_words_free(index_cache->words);
|
||||
rbt_free(index_cache->words);
|
||||
break;
|
||||
}
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
if (index_cache->words) {
|
||||
fts_words_free(index_cache->words);
|
||||
rbt_free(index_cache->words);
|
||||
}
|
||||
|
||||
ib_vector_remove(cache->indexes, *(void**) index_cache);
|
||||
}
|
||||
|
|
|
@ -10877,6 +10877,7 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result))
|
|||
dberr_t
|
||||
innobase_rename_table(
|
||||
/*==================*/
|
||||
THD* thd, /*!< Connection thread handle */
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
const char* from, /*!< in: old name of the table */
|
||||
const char* to) /*!< in: new name of the table */
|
||||
|
@ -10902,6 +10903,36 @@ innobase_rename_table(
|
|||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
dict_table_t* table = dict_table_open_on_name(norm_from, TRUE, FALSE,
|
||||
DICT_ERR_IGNORE_NONE);
|
||||
|
||||
/* Since DICT_BG_YIELD has sleep for 250 milliseconds,
|
||||
Convert lock_wait_timeout unit from second to 250 milliseconds */
|
||||
long int lock_wait_timeout = thd_lock_wait_timeout(thd) * 4;
|
||||
if (table != NULL) {
|
||||
for (dict_index_t* index = dict_table_get_first_index(table);
|
||||
index != NULL;
|
||||
index = dict_table_get_next_index(index)) {
|
||||
|
||||
if (index->type & DICT_FTS) {
|
||||
/* Found */
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)
|
||||
&& (lock_wait_timeout--) > 0) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
}
|
||||
}
|
||||
dict_table_close(table, TRUE, FALSE);
|
||||
}
|
||||
|
||||
/* FTS sync is in progress. We shall timeout this operation */
|
||||
if (lock_wait_timeout < 0) {
|
||||
error = DB_LOCK_WAIT_TIMEOUT;
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
/* Transaction must be flagged as a locking transaction or it hasn't
|
||||
been started yet. */
|
||||
|
||||
|
@ -11011,7 +11042,7 @@ ha_innobase::rename_table(
|
|||
++trx->will_lock;
|
||||
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
|
||||
|
||||
error = innobase_rename_table(trx, from, to);
|
||||
error = innobase_rename_table(thd, trx, from, to);
|
||||
|
||||
DEBUG_SYNC(thd, "after_innobase_rename_table");
|
||||
|
||||
|
@ -11055,6 +11086,10 @@ ha_innobase::rename_table(
|
|||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to);
|
||||
|
||||
error = DB_ERROR;
|
||||
} else if (error == DB_LOCK_WAIT_TIMEOUT) {
|
||||
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), to);
|
||||
|
||||
error = DB_LOCK_WAIT;
|
||||
}
|
||||
|
||||
DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2016, 2018, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
@ -869,37 +869,28 @@ fts_drop_index(
|
|||
|
||||
err = fts_drop_index_tables(trx, index);
|
||||
|
||||
for(;;) {
|
||||
bool retry = false;
|
||||
if (index->index_fts_syncing) {
|
||||
retry = true;
|
||||
}
|
||||
if (!retry){
|
||||
fts_free(table);
|
||||
break;
|
||||
}
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
|
||||
fts_free(table);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
bool retry = false;
|
||||
if (index->index_fts_syncing) {
|
||||
retry = true;
|
||||
}
|
||||
if (!retry){
|
||||
current_doc_id = table->fts->cache->next_doc_id;
|
||||
first_doc_id = table->fts->cache->first_doc_id;
|
||||
fts_cache_clear(table->fts->cache);
|
||||
fts_cache_destroy(table->fts->cache);
|
||||
table->fts->cache = fts_cache_create(table);
|
||||
table->fts->cache->next_doc_id = current_doc_id;
|
||||
table->fts->cache->first_doc_id = first_doc_id;
|
||||
break;
|
||||
}
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
|
||||
current_doc_id = table->fts->cache->next_doc_id;
|
||||
first_doc_id = table->fts->cache->first_doc_id;
|
||||
fts_cache_clear(table->fts->cache);
|
||||
fts_cache_destroy(table->fts->cache);
|
||||
table->fts->cache = fts_cache_create(table);
|
||||
table->fts->cache->next_doc_id = current_doc_id;
|
||||
table->fts->cache->first_doc_id = first_doc_id;
|
||||
} else {
|
||||
fts_cache_t* cache = table->fts->cache;
|
||||
fts_index_cache_t* index_cache;
|
||||
|
@ -909,18 +900,14 @@ fts_drop_index(
|
|||
index_cache = fts_find_index_cache(cache, index);
|
||||
|
||||
if (index_cache != NULL) {
|
||||
for(;;) {
|
||||
bool retry = false;
|
||||
if (index->index_fts_syncing) {
|
||||
retry = true;
|
||||
}
|
||||
if (!retry && index_cache->words) {
|
||||
fts_words_free(index_cache->words);
|
||||
rbt_free(index_cache->words);
|
||||
break;
|
||||
}
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
if (index_cache->words) {
|
||||
fts_words_free(index_cache->words);
|
||||
rbt_free(index_cache->words);
|
||||
}
|
||||
|
||||
ib_vector_remove(cache->indexes, *(void**) index_cache);
|
||||
}
|
||||
|
|
|
@ -11695,6 +11695,7 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result))
|
|||
dberr_t
|
||||
innobase_rename_table(
|
||||
/*==================*/
|
||||
THD* thd, /*!< Connection thread handle */
|
||||
trx_t* trx, /*!< in: transaction */
|
||||
const char* from, /*!< in: old name of the table */
|
||||
const char* to) /*!< in: new name of the table */
|
||||
|
@ -11720,6 +11721,36 @@ innobase_rename_table(
|
|||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
dict_table_t* table = dict_table_open_on_name(norm_from, TRUE, FALSE,
|
||||
DICT_ERR_IGNORE_NONE);
|
||||
|
||||
/* Since DICT_BG_YIELD has sleep for 250 milliseconds,
|
||||
Convert lock_wait_timeout unit from second to 250 milliseconds */
|
||||
long int lock_wait_timeout = thd_lock_wait_timeout(thd) * 4;
|
||||
if (table != NULL) {
|
||||
for (dict_index_t* index = dict_table_get_first_index(table);
|
||||
index != NULL;
|
||||
index = dict_table_get_next_index(index)) {
|
||||
|
||||
if (index->type & DICT_FTS) {
|
||||
/* Found */
|
||||
while (index->index_fts_syncing
|
||||
&& !trx_is_interrupted(trx)
|
||||
&& (lock_wait_timeout--) > 0) {
|
||||
DICT_BG_YIELD(trx);
|
||||
}
|
||||
}
|
||||
}
|
||||
dict_table_close(table, TRUE, FALSE);
|
||||
}
|
||||
|
||||
/* FTS sync is in progress. We shall timeout this operation */
|
||||
if (lock_wait_timeout < 0) {
|
||||
error = DB_LOCK_WAIT_TIMEOUT;
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
/* Transaction must be flagged as a locking transaction or it hasn't
|
||||
been started yet. */
|
||||
|
||||
|
@ -11834,7 +11865,7 @@ ha_innobase::rename_table(
|
|||
++trx->will_lock;
|
||||
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
|
||||
|
||||
error = innobase_rename_table(trx, from, to);
|
||||
error = innobase_rename_table(thd, trx, from, to);
|
||||
|
||||
DEBUG_SYNC(thd, "after_innobase_rename_table");
|
||||
|
||||
|
@ -11878,6 +11909,10 @@ ha_innobase::rename_table(
|
|||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to);
|
||||
|
||||
error = DB_ERROR;
|
||||
} else if (error == DB_LOCK_WAIT_TIMEOUT) {
|
||||
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), to);
|
||||
|
||||
error = DB_LOCK_WAIT;
|
||||
}
|
||||
|
||||
DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
|
||||
|
|
Loading…
Reference in a new issue