1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-19529 InnoDB hang on DROP FULLTEXT INDEX

Problem:
=======
  During dropping of fts index, InnoDB waits for fts_optimize_remove_table()
and it holds dict_sys->mutex and dict_operaiton_lock even though the
table id is not present in the queue. But fts_optimize_thread does wait
for dict_sys->mutex to process the unrelated table id from the slot.

Solution:
========
  Whenever table is added to fts_optimize_wq, update the fts_status
of in-memory fts subsystem to TABLE_IN_QUEUE. Whenever drop index
wants to remove table from the queue, it can check the fts_status
to decide whether it should send the MSG_DELETE_TABLE to the queue.

Removed the following functions because these are all deadcode.
dict_table_wait_for_bg_threads_to_exit(),
fts_wait_for_background_thread_to_start(),fts_start_shutdown(), fts_shudown().
This commit is contained in:
Thirunarayanan Balathandayuthapani
2019-09-18 13:22:08 +05:30
parent 708f1e3419
commit 8a79fa0e4d
26 changed files with 169 additions and 490 deletions

View File

@@ -6,3 +6,21 @@ REPLACE INTO t1(a) VALUES('aaa');
SET DEBUG_SYNC = 'now SIGNAL race';
SET DEBUG_SYNC = 'RESET';
DROP TABLE t1;
#
# MDEV-19529 InnoDB hang on DROP FULLTEXT INDEX
#
CREATE TABLE t1(f1 CHAR(100), FULLTEXT(f1))ENGINE=InnoDB;
INSERT INTO t1 VALUES('test');
CREATE TABLE t2 (f1 char(100), FULLTEXT idx1(f1))ENGINE=InnoDB;
INSERT INTO t2 VALUES('mariadb');
SET GLOBAL debug_dbug ='+d,fts_instrument_sync_request,ib_optimize_wq_hang';
SET DEBUG_SYNC= 'fts_instrument_sync_request
SIGNAL drop_index_start WAIT_FOR sync_op';
INSERT INTO t1 VALUES('Keyword');
SET DEBUG_SYNC='now WAIT_FOR drop_index_start';
SET DEBUG_SYNC= 'norebuild_fts_drop SIGNAL sync_op WAIT_FOR fts_drop_index';
ALTER TABLE t2 drop index idx1;
set DEBUG_SYNC= 'now SIGNAL fts_drop_index';
SET global DEBUG_DBUG=RESET;
drop table t1, t2;
set DEBUG_SYNC=RESET;

View File

@@ -18,3 +18,34 @@ reap;
SET DEBUG_SYNC = 'RESET';
DROP TABLE t1;
--echo #
--echo # MDEV-19529 InnoDB hang on DROP FULLTEXT INDEX
--echo #
CREATE TABLE t1(f1 CHAR(100), FULLTEXT(f1))ENGINE=InnoDB;
INSERT INTO t1 VALUES('test');
CREATE TABLE t2 (f1 char(100), FULLTEXT idx1(f1))ENGINE=InnoDB;
INSERT INTO t2 VALUES('mariadb');
connection default;
SET GLOBAL debug_dbug ='+d,fts_instrument_sync_request,ib_optimize_wq_hang';
SET DEBUG_SYNC= 'fts_instrument_sync_request
SIGNAL drop_index_start WAIT_FOR sync_op';
send INSERT INTO t1 VALUES('Keyword');
connect(con1,localhost,root,,,);
SET DEBUG_SYNC='now WAIT_FOR drop_index_start';
SET DEBUG_SYNC= 'norebuild_fts_drop SIGNAL sync_op WAIT_FOR fts_drop_index';
send ALTER TABLE t2 drop index idx1;
connection default;
reap;
set DEBUG_SYNC= 'now SIGNAL fts_drop_index';
connection con1;
reap;
SET global DEBUG_DBUG=RESET;
drop table t1, t2;
connection default;
set DEBUG_SYNC=RESET;

View File

@@ -2911,33 +2911,6 @@ dict_table_copy_types(
}
}
/********************************************************************
Wait until all the background threads of the given table have exited, i.e.,
bg_threads == 0. Note: bg_threads_mutex must be reserved when
calling this. */
UNIV_INTERN
void
dict_table_wait_for_bg_threads_to_exit(
/*===================================*/
dict_table_t* table, /*< in: table */
ulint delay) /*< in: time in microseconds to wait between
checks of bg_threads. */
{
fts_t* fts = table->fts;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&fts->bg_threads_mutex));
#endif /* UNIV_SYNC_DEBUG */
while (fts->bg_threads > 0) {
mutex_exit(&fts->bg_threads_mutex);
os_thread_sleep(delay);
mutex_enter(&fts->bg_threads_mutex);
}
}
/*******************************************************************//**
Builds the internal dictionary cache representation for a clustered
index, containing also system fields not defined by the user.

View File

@@ -224,8 +224,7 @@ fts_config_set_value(
pars_info_bind_varchar_literal(info, "value",
value->f_str, value->f_len);
const bool dict_locked = fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED;
const bool dict_locked = fts_table->table->fts->dict_locked;
fts_table->suffix = "CONFIG";
fts_get_table_name(fts_table, table_name, dict_locked);

View File

@@ -458,7 +458,7 @@ fts_load_user_stopword(
dberr_t error = DB_SUCCESS;
ibool ret = TRUE;
trx_t* trx;
ibool has_lock = fts->fts_status & TABLE_DICT_LOCKED;
ibool has_lock = fts->dict_locked;
trx = trx_allocate_for_background();
trx->op_info = "Load user stopword table into FTS cache";
@@ -933,18 +933,16 @@ fts_que_graph_free_check_lock(
const fts_index_cache_t*index_cache, /*!< in: FTS index cache */
que_t* graph) /*!< in: query graph */
{
ibool has_dict = FALSE;
bool has_dict = FALSE;
if (fts_table && fts_table->table) {
ut_ad(fts_table->table->fts);
has_dict = fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED;
has_dict = fts_table->table->fts->dict_locked;
} else if (index_cache) {
ut_ad(index_cache->index->table->fts);
has_dict = index_cache->index->table->fts->fts_status
& TABLE_DICT_LOCKED;
has_dict = index_cache->index->table->fts->dict_locked;
}
if (!has_dict) {
@@ -2831,7 +2829,7 @@ fts_update_sync_doc_id(
pars_info_bind_varchar_literal(info, "doc_id", id, id_len);
fts_get_table_name(&fts_table, fts_name,
table->fts->fts_status & TABLE_DICT_LOCKED);
table->fts->dict_locked);
pars_info_bind_id(info, true, "table_name", fts_name);
graph = fts_parse_sql(
@@ -2947,7 +2945,7 @@ fts_delete(
into cache from last crash (delete Doc will not initialize the
sync). Avoid any added counter accounting until the FTS cache
is re-established and sync-ed */
if (table->fts->fts_status & ADDED_TABLE_SYNCED
if (table->fts->added_synced
&& doc_id > cache->synced_doc_id) {
mutex_enter(&table->fts->cache->deleted_lock);
@@ -3385,7 +3383,7 @@ fts_add_doc_by_id(
/* If Doc ID has been supplied by the user, then the table
might not yet be sync-ed */
if (!(ftt->table->fts->fts_status & ADDED_TABLE_SYNCED)) {
if (!ftt->table->fts->added_synced) {
fts_init_index(ftt->table, FALSE);
}
@@ -4933,7 +4931,7 @@ fts_init_doc_id(
fts_init_index((dict_table_t*) table, TRUE);
}
table->fts->fts_status |= ADDED_TABLE_SYNCED;
table->fts->added_synced = true;
table->fts->cache->first_doc_id = max_doc_id;
@@ -5386,69 +5384,6 @@ fts_cache_append_deleted_doc_ids(
mutex_exit((ib_mutex_t*) &cache->deleted_lock);
}
/*********************************************************************//**
Wait for the background thread to start. We poll to detect change
of state, which is acceptable, since the wait should happen only
once during startup.
@return true if the thread started else FALSE (i.e timed out) */
UNIV_INTERN
ibool
fts_wait_for_background_thread_to_start(
/*====================================*/
dict_table_t* table, /*!< in: table to which the thread
is attached */
ulint max_wait) /*!< in: time in microseconds, if
set to 0 then it disables
timeout checking */
{
ulint count = 0;
ibool done = FALSE;
ut_a(max_wait == 0 || max_wait >= FTS_MAX_BACKGROUND_THREAD_WAIT);
for (;;) {
fts_t* fts = table->fts;
mutex_enter(&fts->bg_threads_mutex);
if (fts->fts_status & BG_THREAD_READY) {
done = TRUE;
}
mutex_exit(&fts->bg_threads_mutex);
if (!done) {
os_thread_sleep(FTS_MAX_BACKGROUND_THREAD_WAIT);
if (max_wait > 0) {
max_wait -= FTS_MAX_BACKGROUND_THREAD_WAIT;
/* We ignore the residual value. */
if (max_wait < FTS_MAX_BACKGROUND_THREAD_WAIT) {
break;
}
}
++count;
} else {
break;
}
if (count >= FTS_BACKGROUND_THREAD_WAIT_COUNT) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error the background thread "
"for the FTS table %s refuses to start\n",
table->name);
count = 0;
}
}
return(done);
}
/*********************************************************************//**
Add the FTS document id hidden column. */
UNIV_INTERN
@@ -5589,42 +5524,6 @@ fts_free(
table->fts = NULL;
}
/*********************************************************************//**
Signal FTS threads to initiate shutdown. */
UNIV_INTERN
void
fts_start_shutdown(
/*===============*/
dict_table_t* table, /*!< in: table with FTS indexes */
fts_t* fts) /*!< in: fts instance that needs
to be informed about shutdown */
{
mutex_enter(&fts->bg_threads_mutex);
fts->fts_status |= BG_THREAD_STOP;
mutex_exit(&fts->bg_threads_mutex);
}
/*********************************************************************//**
Wait for FTS threads to shutdown. */
UNIV_INTERN
void
fts_shutdown(
/*=========*/
dict_table_t* table, /*!< in: table with FTS indexes */
fts_t* fts) /*!< in: fts instance to shutdown */
{
mutex_enter(&fts->bg_threads_mutex);
ut_a(fts->fts_status & BG_THREAD_STOP);
dict_table_wait_for_bg_threads_to_exit(table, 20000);
mutex_exit(&fts->bg_threads_mutex);
}
/*********************************************************************//**
Take a FTS savepoint. */
UNIV_INLINE
@@ -7639,7 +7538,7 @@ fts_init_index(
}
rw_lock_x_unlock(&cache->init_lock);
if (table->fts->fts_status & ADDED_TABLE_SYNCED) {
if (table->fts->added_synced) {
goto func_exit;
}
@@ -7681,7 +7580,7 @@ fts_init_index(
}
}
table->fts->fts_status |= ADDED_TABLE_SYNCED;
table->fts->added_synced = true;
fts_get_docs_clear(cache->get_docs);

View File

@@ -2628,6 +2628,10 @@ UNIV_INTERN void fts_optimize_add_table(dict_table_t* table)
msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table);
ib_wqueue_add(fts_optimize_wq, msg, msg->heap);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
}
/**********************************************************************//**
@@ -2656,6 +2660,15 @@ fts_optimize_remove_table(
return;
}
fts_t* fts = table->fts;
mutex_enter(&fts->bg_threads_mutex);
bool is_in_optimize_queue = fts->in_queue;
mutex_exit(&fts->bg_threads_mutex);
if (!is_in_optimize_queue) {
return;
}
msg = fts_optimize_create_msg(FTS_MSG_DEL_TABLE, NULL);
/* We will wait on this event until signalled by the consumer. */
@@ -2673,6 +2686,10 @@ fts_optimize_remove_table(
os_event_wait(event);
os_event_free(event);
mutex_enter(&fts->bg_threads_mutex);
fts->in_queue = false;
mutex_exit(&fts->bg_threads_mutex);
}
/** Send sync fts cache for the table.
@@ -2706,6 +2723,10 @@ fts_optimize_request_sync_table(
msg->ptr = table_id;
ib_wqueue_add(fts_optimize_wq, msg, msg->heap);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
}
/** Add a table to fts_slots if it doesn't already exist. */
@@ -2850,6 +2871,10 @@ static void fts_optimize_sync_table(table_id_t table_id)
fts_sync_table(table, true, false, false);
}
DBUG_EXECUTE_IF(
"ib_optimize_wq_hang",
os_thread_sleep(6000000););
dict_table_close(table, FALSE, FALSE);
}
}

View File

@@ -165,8 +165,7 @@ fts_parse_sql(
str = ut_str3cat(fts_sql_begin, sql, fts_sql_end);
dict_locked = (fts_table && fts_table->table->fts
&& (fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED));
&& fts_table->table->fts->dict_locked);
if (!dict_locked) {
ut_ad(!mutex_own(&(dict_sys->mutex)));

View File

@@ -10094,10 +10094,10 @@ ha_innobase::ft_init_ext(
return(NULL);
}
if (!(ft_table->fts->fts_status & ADDED_TABLE_SYNCED)) {
if (!(ft_table->fts->added_synced)) {
fts_init_index(ft_table, FALSE);
ft_table->fts->fts_status |= ADDED_TABLE_SYNCED;
ft_table->fts->added_synced = true;
}
error = fts_query(trx, index, flags, query, query_len, &result);

View File

@@ -3245,15 +3245,13 @@ op_ok:
goto error_handling;
}
ctx->new_table->fts->fts_status
|= TABLE_DICT_LOCKED;
ctx->new_table->fts->dict_locked = true;
error = innobase_fts_load_stopword(
ctx->new_table, ctx->trx,
ctx->prebuilt->trx->mysql_thd)
? DB_SUCCESS : DB_ERROR;
ctx->new_table->fts->fts_status
&= ~TABLE_DICT_LOCKED;
ctx->new_table->fts->dict_locked = false;
if (error != DB_SUCCESS) {
goto error_handling;
@@ -5624,6 +5622,7 @@ commit_cache_norebuild(
|| (index->type
& DICT_CORRUPT));
DBUG_ASSERT(index->table->fts);
DEBUG_SYNC_C("norebuild_fts_drop");
fts_drop_index(index->table, index, trx);
}

View File

@@ -1016,18 +1016,6 @@ dict_table_copy_types(
dtuple_t* tuple, /*!< in/out: data tuple */
const dict_table_t* table) /*!< in: table */
MY_ATTRIBUTE((nonnull));
/********************************************************************
Wait until all the background threads of the given table have exited, i.e.,
bg_threads == 0. Note: bg_threads_mutex must be reserved when
calling this. */
UNIV_INTERN
void
dict_table_wait_for_bg_threads_to_exit(
/*===================================*/
dict_table_t* table, /* in: table */
ulint delay) /* in: time in microseconds to wait between
checks of bg_threads. */
MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Looks for an index with the given id. NOTE that we do not reserve
the dictionary mutex: this function is for emergency purposes like

View File

@@ -279,40 +279,21 @@ struct fts_table_t {
index auxiliary table */
};
enum fts_status {
BG_THREAD_STOP = 1, /*!< TRUE if the FTS background thread
has finished reading the ADDED table,
meaning more items can be added to
the table. */
BG_THREAD_READY = 2, /*!< TRUE if the FTS background thread
is ready */
ADD_THREAD_STARTED = 4, /*!< TRUE if the FTS add thread
has started */
ADDED_TABLE_SYNCED = 8, /*!< TRUE if the ADDED table record is
sync-ed after crash recovery */
TABLE_DICT_LOCKED = 16 /*!< Set if the table has
dict_sys->mutex */
};
typedef enum fts_status fts_status_t;
/** The state of the FTS sub system. */
struct fts_t {
/*!< mutex protecting bg_threads* and
fts_add_wq. */
ib_mutex_t bg_threads_mutex;
ulint bg_threads; /*!< number of background threads
accessing this table */
/*!< TRUE if background threads running
should stop themselves */
ulint fts_status; /*!< Status bit regarding fts
running state */
/* Wheter the table was added to fts_optimize_wq();
protected by bg_threads mutex */
unsigned in_queue:1;
/* Whether the ADDED table record sync-ed after
crash recovery; protected by bg_threads mutex */
unsigned added_synced:1;
/* Whether the table hold dict_sys->mutex;
protected by bg_threads mutex */
unsigned dict_locked:1;
ib_wqueue_t* add_wq; /*!< Work queue for scheduling jobs
for the FTS 'Add' thread, or NULL
@@ -614,28 +595,6 @@ void
fts_startup(void);
/*==============*/
/******************************************************************//**
Signal FTS threads to initiate shutdown. */
UNIV_INTERN
void
fts_start_shutdown(
/*===============*/
dict_table_t* table, /*!< in: table with FTS
indexes */
fts_t* fts); /*!< in: fts instance to
shutdown */
/******************************************************************//**
Wait for FTS threads to shutdown. */
UNIV_INTERN
void
fts_shutdown(
/*=========*/
dict_table_t* table, /*!< in: table with FTS
indexes */
fts_t* fts); /*!< in: fts instance to
shutdown */
/******************************************************************//**
Create an instance of fts_t.
@return instance of fts_t */

View File

@@ -521,20 +521,6 @@ fts_cache_append_deleted_doc_ids(
const fts_cache_t*
cache, /*!< in: cache to use */
ib_vector_t* vector); /*!< in: append to this vector */
/******************************************************************//**
Wait for the background thread to start. We poll to detect change
of state, which is acceptable, since the wait should happen only
once during startup.
@return true if the thread started else FALSE (i.e timed out) */
UNIV_INTERN
ibool
fts_wait_for_background_thread_to_start(
/*====================================*/
dict_table_t* table, /*!< in: table to which the thread
is attached */
ulint max_wait); /*!< in: time in microseconds, if set
to 0 then it disables timeout
checking */
#ifdef FTS_DOC_STATS_DEBUG
/******************************************************************//**
Get the total number of words in the FTS for a particular FTS index.

View File

@@ -3829,11 +3829,11 @@ next_rec:
DBUG_EXECUTE_IF("ib_trunc_sleep_before_fts_cache_clear",
os_thread_sleep(10000000););
table->fts->fts_status |= TABLE_DICT_LOCKED;
table->fts->dict_locked = true;
fts_update_next_doc_id(trx, table, 0);
fts_cache_clear(table->fts->cache);
fts_cache_init(table->fts->cache);
table->fts->fts_status &= ~TABLE_DICT_LOCKED;
table->fts->dict_locked = false;
}
}
@@ -4434,8 +4434,7 @@ do_drop:
/* Need to set TABLE_DICT_LOCKED bit, since
fts_que_graph_free_check_lock would try to acquire
dict mutex lock */
table->fts->fts_status |= TABLE_DICT_LOCKED;
table->fts->dict_locked = true;
fts_free(table);
}

View File

@@ -1062,27 +1062,16 @@ trx_finalize_for_fts_table(
{
fts_t* fts = ftt->table->fts;
fts_doc_ids_t* doc_ids = ftt->added_doc_ids;
mem_heap_t* heap;
mutex_enter(&fts->bg_threads_mutex);
ut_a(fts->add_wq);
if (fts->fts_status & BG_THREAD_STOP) {
/* The table is about to be dropped, no use
adding anything to its work queue. */
heap = static_cast<mem_heap_t*>(doc_ids->self_heap->arg);
mutex_exit(&fts->bg_threads_mutex);
} else {
mem_heap_t* heap;
mutex_exit(&fts->bg_threads_mutex);
ib_wqueue_add(fts->add_wq, doc_ids, heap);
ut_a(fts->add_wq);
heap = static_cast<mem_heap_t*>(doc_ids->self_heap->arg);
ib_wqueue_add(fts->add_wq, doc_ids, heap);
/* fts_trx_table_t no longer owns the list. */
ftt->added_doc_ids = NULL;
}
/* fts_trx_table_t no longer owns the list. */
ftt->added_doc_ids = NULL;
}
/******************************************************************//**

View File

@@ -2921,33 +2921,6 @@ dict_table_copy_types(
}
}
/********************************************************************
Wait until all the background threads of the given table have exited, i.e.,
bg_threads == 0. Note: bg_threads_mutex must be reserved when
calling this. */
UNIV_INTERN
void
dict_table_wait_for_bg_threads_to_exit(
/*===================================*/
dict_table_t* table, /*< in: table */
ulint delay) /*< in: time in microseconds to wait between
checks of bg_threads. */
{
fts_t* fts = table->fts;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&fts->bg_threads_mutex));
#endif /* UNIV_SYNC_DEBUG */
while (fts->bg_threads > 0) {
mutex_exit(&fts->bg_threads_mutex);
os_thread_sleep(delay);
mutex_enter(&fts->bg_threads_mutex);
}
}
/*******************************************************************//**
Builds the internal dictionary cache representation for a clustered
index, containing also system fields not defined by the user.

View File

@@ -224,8 +224,7 @@ fts_config_set_value(
pars_info_bind_varchar_literal(info, "value",
value->f_str, value->f_len);
const bool dict_locked = fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED;
const bool dict_locked = fts_table->table->fts->dict_locked;
fts_table->suffix = "CONFIG";
fts_get_table_name(fts_table, table_name, dict_locked);

View File

@@ -458,7 +458,7 @@ fts_load_user_stopword(
dberr_t error = DB_SUCCESS;
ibool ret = TRUE;
trx_t* trx;
ibool has_lock = fts->fts_status & TABLE_DICT_LOCKED;
ibool has_lock = fts->dict_locked;
trx = trx_allocate_for_background();
trx->op_info = "Load user stopword table into FTS cache";
@@ -933,18 +933,16 @@ fts_que_graph_free_check_lock(
const fts_index_cache_t*index_cache, /*!< in: FTS index cache */
que_t* graph) /*!< in: query graph */
{
ibool has_dict = FALSE;
bool has_dict = FALSE;
if (fts_table && fts_table->table) {
ut_ad(fts_table->table->fts);
has_dict = fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED;
has_dict = fts_table->table->fts->dict_locked;
} else if (index_cache) {
ut_ad(index_cache->index->table->fts);
has_dict = index_cache->index->table->fts->fts_status
& TABLE_DICT_LOCKED;
has_dict = index_cache->index->table->fts->dict_locked;
}
if (!has_dict) {
@@ -2831,7 +2829,7 @@ fts_update_sync_doc_id(
pars_info_bind_varchar_literal(info, "doc_id", id, id_len);
fts_get_table_name(&fts_table, fts_name,
table->fts->fts_status & TABLE_DICT_LOCKED);
table->fts->dict_locked);
pars_info_bind_id(info, true, "table_name", fts_name);
graph = fts_parse_sql(
@@ -2947,7 +2945,7 @@ fts_delete(
into cache from last crash (delete Doc will not initialize the
sync). Avoid any added counter accounting until the FTS cache
is re-established and sync-ed */
if (table->fts->fts_status & ADDED_TABLE_SYNCED
if (table->fts->added_synced
&& doc_id > cache->synced_doc_id) {
mutex_enter(&table->fts->cache->deleted_lock);
@@ -3385,7 +3383,7 @@ fts_add_doc_by_id(
/* If Doc ID has been supplied by the user, then the table
might not yet be sync-ed */
if (!(ftt->table->fts->fts_status & ADDED_TABLE_SYNCED)) {
if (!ftt->table->fts->added_synced) {
fts_init_index(ftt->table, FALSE);
}
@@ -4933,7 +4931,7 @@ fts_init_doc_id(
fts_init_index((dict_table_t*) table, TRUE);
}
table->fts->fts_status |= ADDED_TABLE_SYNCED;
table->fts->added_synced = true;
table->fts->cache->first_doc_id = max_doc_id;
@@ -5386,69 +5384,6 @@ fts_cache_append_deleted_doc_ids(
mutex_exit((ib_mutex_t*) &cache->deleted_lock);
}
/*********************************************************************//**
Wait for the background thread to start. We poll to detect change
of state, which is acceptable, since the wait should happen only
once during startup.
@return true if the thread started else FALSE (i.e timed out) */
UNIV_INTERN
ibool
fts_wait_for_background_thread_to_start(
/*====================================*/
dict_table_t* table, /*!< in: table to which the thread
is attached */
ulint max_wait) /*!< in: time in microseconds, if
set to 0 then it disables
timeout checking */
{
ulint count = 0;
ibool done = FALSE;
ut_a(max_wait == 0 || max_wait >= FTS_MAX_BACKGROUND_THREAD_WAIT);
for (;;) {
fts_t* fts = table->fts;
mutex_enter(&fts->bg_threads_mutex);
if (fts->fts_status & BG_THREAD_READY) {
done = TRUE;
}
mutex_exit(&fts->bg_threads_mutex);
if (!done) {
os_thread_sleep(FTS_MAX_BACKGROUND_THREAD_WAIT);
if (max_wait > 0) {
max_wait -= FTS_MAX_BACKGROUND_THREAD_WAIT;
/* We ignore the residual value. */
if (max_wait < FTS_MAX_BACKGROUND_THREAD_WAIT) {
break;
}
}
++count;
} else {
break;
}
if (count >= FTS_BACKGROUND_THREAD_WAIT_COUNT) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error the background thread "
"for the FTS table %s refuses to start\n",
table->name);
count = 0;
}
}
return(done);
}
/*********************************************************************//**
Add the FTS document id hidden column. */
UNIV_INTERN
@@ -5589,42 +5524,6 @@ fts_free(
table->fts = NULL;
}
/*********************************************************************//**
Signal FTS threads to initiate shutdown. */
UNIV_INTERN
void
fts_start_shutdown(
/*===============*/
dict_table_t* table, /*!< in: table with FTS indexes */
fts_t* fts) /*!< in: fts instance that needs
to be informed about shutdown */
{
mutex_enter(&fts->bg_threads_mutex);
fts->fts_status |= BG_THREAD_STOP;
mutex_exit(&fts->bg_threads_mutex);
}
/*********************************************************************//**
Wait for FTS threads to shutdown. */
UNIV_INTERN
void
fts_shutdown(
/*=========*/
dict_table_t* table, /*!< in: table with FTS indexes */
fts_t* fts) /*!< in: fts instance to shutdown */
{
mutex_enter(&fts->bg_threads_mutex);
ut_a(fts->fts_status & BG_THREAD_STOP);
dict_table_wait_for_bg_threads_to_exit(table, 20000);
mutex_exit(&fts->bg_threads_mutex);
}
/*********************************************************************//**
Take a FTS savepoint. */
UNIV_INLINE
@@ -7639,7 +7538,7 @@ fts_init_index(
}
rw_lock_x_unlock(&cache->init_lock);
if (table->fts->fts_status & ADDED_TABLE_SYNCED) {
if (table->fts->added_synced) {
goto func_exit;
}
@@ -7681,7 +7580,7 @@ fts_init_index(
}
}
table->fts->fts_status |= ADDED_TABLE_SYNCED;
table->fts->added_synced = true;
fts_get_docs_clear(cache->get_docs);

View File

@@ -2628,6 +2628,10 @@ UNIV_INTERN void fts_optimize_add_table(dict_table_t* table)
msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table);
ib_wqueue_add(fts_optimize_wq, msg, msg->heap);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
}
/**********************************************************************//**
@@ -2656,6 +2660,15 @@ fts_optimize_remove_table(
return;
}
fts_t* fts = table->fts;
mutex_enter(&fts->bg_threads_mutex);
bool is_in_optimize_queue = fts->in_queue;
mutex_exit(&fts->bg_threads_mutex);
if (!is_in_optimize_queue) {
return;
}
msg = fts_optimize_create_msg(FTS_MSG_DEL_TABLE, NULL);
/* We will wait on this event until signalled by the consumer. */
@@ -2673,6 +2686,10 @@ fts_optimize_remove_table(
os_event_wait(event);
os_event_free(event);
mutex_enter(&fts->bg_threads_mutex);
fts->in_queue = false;
mutex_exit(&fts->bg_threads_mutex);
}
/** Send sync fts cache for the table.
@@ -2706,6 +2723,10 @@ fts_optimize_request_sync_table(
msg->ptr = table_id;
ib_wqueue_add(fts_optimize_wq, msg, msg->heap);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
}
/** Add a table to fts_slots if it doesn't already exist. */
@@ -2850,6 +2871,10 @@ static void fts_optimize_sync_table(table_id_t table_id)
fts_sync_table(table, true, false, false);
}
DBUG_EXECUTE_IF(
"ib_optimize_wq_hang",
os_thread_sleep(6000000););
dict_table_close(table, FALSE, FALSE);
}
}

View File

@@ -165,8 +165,7 @@ fts_parse_sql(
str = ut_str3cat(fts_sql_begin, sql, fts_sql_end);
dict_locked = (fts_table && fts_table->table->fts
&& (fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED));
&& fts_table->table->fts->dict_locked);
if (!dict_locked) {
ut_ad(!mutex_own(&(dict_sys->mutex)));

View File

@@ -10640,10 +10640,10 @@ ha_innobase::ft_init_ext(
return(NULL);
}
if (!(ft_table->fts->fts_status & ADDED_TABLE_SYNCED)) {
if (!(ft_table->fts->added_synced)) {
fts_init_index(ft_table, FALSE);
ft_table->fts->fts_status |= ADDED_TABLE_SYNCED;
ft_table->fts->added_synced = true;
}
error = fts_query(trx, index, flags, query, query_len, &result);

View File

@@ -3252,15 +3252,13 @@ op_ok:
goto error_handling;
}
ctx->new_table->fts->fts_status
|= TABLE_DICT_LOCKED;
ctx->new_table->fts->dict_locked = true;
error = innobase_fts_load_stopword(
ctx->new_table, ctx->trx,
ctx->prebuilt->trx->mysql_thd)
? DB_SUCCESS : DB_ERROR;
ctx->new_table->fts->fts_status
&= ~TABLE_DICT_LOCKED;
ctx->new_table->fts->dict_locked = false;
if (error != DB_SUCCESS) {
goto error_handling;
@@ -5642,6 +5640,7 @@ commit_cache_norebuild(
|| (index->type
& DICT_CORRUPT));
DBUG_ASSERT(index->table->fts);
DEBUG_SYNC_C("norebuild_fts_drop");
fts_drop_index(index->table, index, trx);
}

View File

@@ -1015,18 +1015,6 @@ dict_table_copy_types(
dtuple_t* tuple, /*!< in/out: data tuple */
const dict_table_t* table) /*!< in: table */
MY_ATTRIBUTE((nonnull));
/********************************************************************
Wait until all the background threads of the given table have exited, i.e.,
bg_threads == 0. Note: bg_threads_mutex must be reserved when
calling this. */
UNIV_INTERN
void
dict_table_wait_for_bg_threads_to_exit(
/*===================================*/
dict_table_t* table, /* in: table */
ulint delay) /* in: time in microseconds to wait between
checks of bg_threads. */
MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Looks for an index with the given id. NOTE that we do not reserve
the dictionary mutex: this function is for emergency purposes like

View File

@@ -279,40 +279,21 @@ struct fts_table_t {
index auxiliary table */
};
enum fts_status {
BG_THREAD_STOP = 1, /*!< TRUE if the FTS background thread
has finished reading the ADDED table,
meaning more items can be added to
the table. */
BG_THREAD_READY = 2, /*!< TRUE if the FTS background thread
is ready */
ADD_THREAD_STARTED = 4, /*!< TRUE if the FTS add thread
has started */
ADDED_TABLE_SYNCED = 8, /*!< TRUE if the ADDED table record is
sync-ed after crash recovery */
TABLE_DICT_LOCKED = 16 /*!< Set if the table has
dict_sys->mutex */
};
typedef enum fts_status fts_status_t;
/** The state of the FTS sub system. */
struct fts_t {
/*!< mutex protecting bg_threads* and
fts_add_wq. */
ib_mutex_t bg_threads_mutex;
ulint bg_threads; /*!< number of background threads
accessing this table */
/*!< TRUE if background threads running
should stop themselves */
ulint fts_status; /*!< Status bit regarding fts
running state */
/* Whether the table was added to fts_optimize_wq();
protected by bg_threads mutex */
unsigned in_queue:1;
/* Whether the ADDED table record sync-ed afer
crash recovery; protected by bg_threads mutex */
unsigned added_synced:1;
/* Whether the table hold dict_sys->mutex;
protected by bg_threads mutex */
unsigned dict_locked:1;
ib_wqueue_t* add_wq; /*!< Work queue for scheduling jobs
for the FTS 'Add' thread, or NULL
@@ -614,28 +595,6 @@ void
fts_startup(void);
/*==============*/
/******************************************************************//**
Signal FTS threads to initiate shutdown. */
UNIV_INTERN
void
fts_start_shutdown(
/*===============*/
dict_table_t* table, /*!< in: table with FTS
indexes */
fts_t* fts); /*!< in: fts instance to
shutdown */
/******************************************************************//**
Wait for FTS threads to shutdown. */
UNIV_INTERN
void
fts_shutdown(
/*=========*/
dict_table_t* table, /*!< in: table with FTS
indexes */
fts_t* fts); /*!< in: fts instance to
shutdown */
/******************************************************************//**
Create an instance of fts_t.
@return instance of fts_t */

View File

@@ -521,20 +521,6 @@ fts_cache_append_deleted_doc_ids(
const fts_cache_t*
cache, /*!< in: cache to use */
ib_vector_t* vector); /*!< in: append to this vector */
/******************************************************************//**
Wait for the background thread to start. We poll to detect change
of state, which is acceptable, since the wait should happen only
once during startup.
@return true if the thread started else FALSE (i.e timed out) */
UNIV_INTERN
ibool
fts_wait_for_background_thread_to_start(
/*====================================*/
dict_table_t* table, /*!< in: table to which the thread
is attached */
ulint max_wait); /*!< in: time in microseconds, if set
to 0 then it disables timeout
checking */
#ifdef FTS_DOC_STATS_DEBUG
/******************************************************************//**
Get the total number of words in the FTS for a particular FTS index.

View File

@@ -3839,11 +3839,11 @@ next_rec:
DBUG_EXECUTE_IF("ib_trunc_sleep_before_fts_cache_clear",
os_thread_sleep(10000000););
table->fts->fts_status |= TABLE_DICT_LOCKED;
table->fts->dict_locked = true;
fts_update_next_doc_id(trx, table, 0);
fts_cache_clear(table->fts->cache);
fts_cache_init(table->fts->cache);
table->fts->fts_status &= ~TABLE_DICT_LOCKED;
table->fts->dict_locked = false;
}
}
@@ -4444,8 +4444,7 @@ do_drop:
/* Need to set TABLE_DICT_LOCKED bit, since
fts_que_graph_free_check_lock would try to acquire
dict mutex lock */
table->fts->fts_status |= TABLE_DICT_LOCKED;
table->fts->dict_locked = true;
fts_free(table);
}

View File

@@ -1269,27 +1269,16 @@ trx_finalize_for_fts_table(
{
fts_t* fts = ftt->table->fts;
fts_doc_ids_t* doc_ids = ftt->added_doc_ids;
mem_heap_t* heap;
mutex_enter(&fts->bg_threads_mutex);
ut_a(fts->add_wq);
if (fts->fts_status & BG_THREAD_STOP) {
/* The table is about to be dropped, no use
adding anything to its work queue. */
heap = static_cast<mem_heap_t*>(doc_ids->self_heap->arg);
mutex_exit(&fts->bg_threads_mutex);
} else {
mem_heap_t* heap;
mutex_exit(&fts->bg_threads_mutex);
ib_wqueue_add(fts->add_wq, doc_ids, heap);
ut_a(fts->add_wq);
heap = static_cast<mem_heap_t*>(doc_ids->self_heap->arg);
ib_wqueue_add(fts->add_wq, doc_ids, heap);
/* fts_trx_table_t no longer owns the list. */
ftt->added_doc_ids = NULL;
}
/* fts_trx_table_t no longer owns the list. */
ftt->added_doc_ids = NULL;
}
/******************************************************************//**