Skip to content

Commit a4ea462

Browse files
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 : [email protected]
1 parent a50fcc1 commit a4ea462

File tree

2 files changed

+66
-41
lines changed

2 files changed

+66
-41
lines changed

storage/innobase/fts/fts0fts.cc

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved.
3+
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
44
55
This program is free software; you can redistribute it and/or modify it under
66
the terms of the GNU General Public License as published by the Free Software
@@ -868,37 +868,28 @@ fts_drop_index(
868868

869869
err = fts_drop_index_tables(trx, index);
870870

871-
for(;;) {
872-
bool retry = false;
873-
if (index->index_fts_syncing) {
874-
retry = true;
875-
}
876-
if (!retry){
877-
fts_free(table);
878-
break;
879-
}
880-
DICT_BG_YIELD(trx);
881-
}
871+
while (index->index_fts_syncing
872+
&& !trx_is_interrupted(trx)) {
873+
DICT_BG_YIELD(trx);
874+
}
875+
876+
fts_free(table);
877+
882878
return(err);
883879
}
884880

885-
for(;;) {
886-
bool retry = false;
887-
if (index->index_fts_syncing) {
888-
retry = true;
889-
}
890-
if (!retry){
891-
current_doc_id = table->fts->cache->next_doc_id;
892-
first_doc_id = table->fts->cache->first_doc_id;
893-
fts_cache_clear(table->fts->cache);
894-
fts_cache_destroy(table->fts->cache);
895-
table->fts->cache = fts_cache_create(table);
896-
table->fts->cache->next_doc_id = current_doc_id;
897-
table->fts->cache->first_doc_id = first_doc_id;
898-
break;
899-
}
900-
DICT_BG_YIELD(trx);
901-
}
881+
while (index->index_fts_syncing
882+
&& !trx_is_interrupted(trx)) {
883+
DICT_BG_YIELD(trx);
884+
}
885+
886+
current_doc_id = table->fts->cache->next_doc_id;
887+
first_doc_id = table->fts->cache->first_doc_id;
888+
fts_cache_clear(table->fts->cache);
889+
fts_cache_destroy(table->fts->cache);
890+
table->fts->cache = fts_cache_create(table);
891+
table->fts->cache->next_doc_id = current_doc_id;
892+
table->fts->cache->first_doc_id = first_doc_id;
902893
} else {
903894
fts_cache_t* cache = table->fts->cache;
904895
fts_index_cache_t* index_cache;
@@ -908,17 +899,13 @@ fts_drop_index(
908899
index_cache = fts_find_index_cache(cache, index);
909900

910901
if (index_cache != NULL) {
911-
for(;;) {
912-
bool retry = false;
913-
if (index->index_fts_syncing) {
914-
retry = true;
915-
}
916-
if (!retry && index_cache->words) {
917-
fts_words_free(index_cache->words);
918-
rbt_free(index_cache->words);
919-
break;
920-
}
921-
DICT_BG_YIELD(trx);
902+
while (index->index_fts_syncing
903+
&& !trx_is_interrupted(trx)) {
904+
DICT_BG_YIELD(trx);
905+
}
906+
if (index_cache->words) {
907+
fts_words_free(index_cache->words);
908+
rbt_free(index_cache->words);
922909
}
923910

924911
ib_vector_remove(cache->indexes, *(void**) index_cache);

storage/innobase/handler/ha_innodb.cc

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10364,6 +10364,7 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result))
1036410364
dberr_t
1036510365
innobase_rename_table(
1036610366
/*==================*/
10367+
THD* thd, /*!< Connection thread handle */
1036710368
trx_t* trx, /*!< in: transaction */
1036810369
const char* from, /*!< in: old name of the table */
1036910370
const char* to) /*!< in: new name of the table */
@@ -10389,6 +10390,37 @@ innobase_rename_table(
1038910390

1039010391
row_mysql_lock_data_dictionary(trx);
1039110392

10393+
dict_table_t* table = NULL;
10394+
table = dict_table_open_on_name(norm_from, TRUE, FALSE,
10395+
DICT_ERR_IGNORE_NONE);
10396+
10397+
/* Since DICT_BG_YIELD has sleep for 250 milliseconds,
10398+
Convert lock_wait_timeout unit from second to 250 milliseconds */
10399+
long int lock_wait_timeout = thd_lock_wait_timeout(thd) * 4;
10400+
if (table != NULL) {
10401+
for (dict_index_t* index = dict_table_get_first_index(table);
10402+
index != NULL;
10403+
index = dict_table_get_next_index(index)) {
10404+
10405+
if (index->type & DICT_FTS) {
10406+
/* Found */
10407+
while (index->index_fts_syncing
10408+
&& !trx_is_interrupted(trx)
10409+
&& (lock_wait_timeout--) > 0) {
10410+
DICT_BG_YIELD(trx);
10411+
}
10412+
}
10413+
}
10414+
dict_table_close(table, TRUE, FALSE);
10415+
}
10416+
10417+
/* FTS sync is in progress. We shall timeout this operation */
10418+
if (lock_wait_timeout < 0) {
10419+
error = DB_LOCK_WAIT_TIMEOUT;
10420+
row_mysql_unlock_data_dictionary(trx);
10421+
DBUG_RETURN(error);
10422+
}
10423+
1039210424
/* Transaction must be flagged as a locking transaction or it hasn't
1039310425
been started yet. */
1039410426

@@ -10498,7 +10530,7 @@ ha_innobase::rename_table(
1049810530
++trx->will_lock;
1049910531
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1050010532

10501-
error = innobase_rename_table(trx, from, to);
10533+
error = innobase_rename_table(thd, trx, from, to);
1050210534

1050310535
DEBUG_SYNC(thd, "after_innobase_rename_table");
1050410536

@@ -10544,6 +10576,12 @@ ha_innobase::rename_table(
1054410576
error = DB_ERROR;
1054510577
}
1054610578

10579+
else if (error == DB_LOCK_WAIT_TIMEOUT) {
10580+
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), to);
10581+
10582+
error = DB_LOCK_WAIT;
10583+
}
10584+
1054710585
DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
1054810586
}
1054910587

0 commit comments

Comments
 (0)