Commit 5b3f7c0c authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-18220: Remove some redundant data structures

fts_state_t, fts_slot_t::state: Remove. Replaced by fts_slot_t::running
and fts_slot_t::table_id as follows.

FTS_STATE_SUSPENDED: Removed (unused).

FTS_STATE_EMPTY: Removed. table_id=0 will denote empty slots.

FTS_STATE_RUNNING: Equivalent to running=true.

FTS_STATE_LOADED, FTS_STATE_DONE: Equivalent to running=false.

fts_slot_t::table: Remove. Tables will be identified by table_id.
After opening a table, we will check fil_table_accessible() before
accessing the data.

fts_optimize_new_table(), fts_optimize_del_table(),
fts_optimize_how_many(), fts_is_sync_needed():
Remove the parameter tables, and use the static variable fts_slots
(which was introduced in MariaDB 10.2) instead.
parent 06442e3e
...@@ -2773,6 +2773,29 @@ fil_close_tablespace( ...@@ -2773,6 +2773,29 @@ fil_close_tablespace(
return(err); return(err);
} }
/** Determine whether a table can be accessed in operations that are
not (necessarily) protected by meta-data locks.
(Rollback would generally be protected, but rollback of
FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks
but only by InnoDB table locks, which may be broken by
lock_remove_all_on_table().)
@param[in] table persistent table
checked @return whether the table is accessible */
UNIV_INTERN bool fil_table_accessible(const dict_table_t* table)
{
if (UNIV_UNLIKELY(!table->is_readable() || table->corrupted)) {
return(false);
}
if (fil_space_t* space = fil_space_acquire(table->space)) {
bool accessible = !space->is_stopping();
fil_space_release(space);
return(accessible);
} else {
return(false);
}
}
/** Delete a tablespace and associated .ibd file. /** Delete a tablespace and associated .ibd file.
@param[in] id tablespace identifier @param[in] id tablespace identifier
@param[in] drop_ahi whether to drop the adaptive hash index @param[in] drop_ahi whether to drop the adaptive hash index
......
...@@ -43,6 +43,9 @@ Completed 2011/7/10 Sunny and Jimmy Yang ...@@ -43,6 +43,9 @@ Completed 2011/7/10 Sunny and Jimmy Yang
/** The FTS optimize thread's work queue. */ /** The FTS optimize thread's work queue. */
static ib_wqueue_t* fts_optimize_wq; static ib_wqueue_t* fts_optimize_wq;
/** The FTS vector to store fts_slot_t */
static ib_vector_t* fts_slots;
/** Time to wait for a message. */ /** Time to wait for a message. */
static const ulint FTS_QUEUE_WAIT_IN_USECS = 5000000; static const ulint FTS_QUEUE_WAIT_IN_USECS = 5000000;
...@@ -58,15 +61,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64; ...@@ -58,15 +61,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64;
/** Last time we did check whether system need a sync */ /** Last time we did check whether system need a sync */
static ib_time_t last_check_sync_time; static ib_time_t last_check_sync_time;
/** State of a table within the optimization sub system. */
enum fts_state_t {
FTS_STATE_LOADED,
FTS_STATE_RUNNING,
FTS_STATE_SUSPENDED,
FTS_STATE_DONE,
FTS_STATE_EMPTY
};
/** FTS optimize thread message types. */ /** FTS optimize thread message types. */
enum fts_msg_type_t { enum fts_msg_type_t {
FTS_MSG_STOP, /*!< Stop optimizing and exit thread */ FTS_MSG_STOP, /*!< Stop optimizing and exit thread */
...@@ -175,11 +169,11 @@ struct fts_encode_t { ...@@ -175,11 +169,11 @@ struct fts_encode_t {
/** We use this information to determine when to start the optimize /** We use this information to determine when to start the optimize
cycle for a table. */ cycle for a table. */
struct fts_slot_t { struct fts_slot_t {
dict_table_t* table; /*!< Table to optimize */ /** table identifier, or 0 if the slot is empty */
table_id_t table_id;
table_id_t table_id; /*!< Table id */
fts_state_t state; /*!< State of this slot */ /** whether this slot is being processed */
bool running;
ulint added; /*!< Number of doc ids added since the ulint added; /*!< Number of doc ids added since the
last time this table was optimized */ last time this table was optimized */
...@@ -2404,31 +2398,35 @@ fts_optimize_table_bk( ...@@ -2404,31 +2398,35 @@ fts_optimize_table_bk(
fts_slot_t* slot) /*!< in: table to optimiza */ fts_slot_t* slot) /*!< in: table to optimiza */
{ {
dberr_t error; dberr_t error;
dict_table_t* table = slot->table;
fts_t* fts = table->fts;
/* Avoid optimizing tables that were optimized recently. */ /* Avoid optimizing tables that were optimized recently. */
if (slot->last_run > 0 if (slot->last_run > 0
&& (ut_time() - slot->last_run) < slot->interval_time) { && (ut_time() - slot->last_run) < slot->interval_time) {
return(DB_SUCCESS); return(DB_SUCCESS);
}
} else if (fts && fts->cache dict_table_t* table = dict_table_open_on_id(
&& fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) { slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (table && fil_table_accessible(table)
&& table->fts && table->fts->cache
&& table->fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) {
error = fts_optimize_table(table); error = fts_optimize_table(table);
slot->last_run = ut_time();
if (error == DB_SUCCESS) { if (error == DB_SUCCESS) {
slot->state = FTS_STATE_DONE; slot->running = false;
slot->last_run = 0; slot->completed = slot->last_run;
slot->completed = ut_time();
} }
} else { } else {
/* Note time this run completed. */
slot->last_run = ut_time();
error = DB_SUCCESS; error = DB_SUCCESS;
} }
/* Note time this run completed. */ dict_table_close(table, FALSE, FALSE);
slot->last_run = ut_time();
return(error); return(error);
} }
...@@ -2647,85 +2645,60 @@ fts_optimize_request_sync_table( ...@@ -2647,85 +2645,60 @@ fts_optimize_request_sync_table(
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); ib_wqueue_add(fts_optimize_wq, msg, msg->heap);
} }
/**********************************************************************//** /** Add a table to fts_slots if it doesn't already exist. */
Add the table to the vector if it doesn't already exist. */ static bool fts_optimize_new_table(dict_table_t* table)
static
ibool
fts_optimize_new_table(
/*===================*/
ib_vector_t* tables, /*!< in/out: vector of tables */
dict_table_t* table) /*!< in: table to add */
{ {
ulint i; ulint i;
fts_slot_t* slot; fts_slot_t* slot;
ulint empty_slot = ULINT_UNDEFINED; fts_slot_t* empty = NULL;
const table_id_t table_id = table->id;
ut_ad(table_id);
/* Search for duplicates, also find a free slot if one exists. */ /* Search for duplicates, also find a free slot if one exists. */
for (i = 0; i < ib_vector_size(tables); ++i) { for (i = 0; i < ib_vector_size(fts_slots); ++i) {
slot = static_cast<fts_slot_t*>( slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
ib_vector_get(tables, i));
if (slot->state == FTS_STATE_EMPTY) { if (!slot->table_id) {
empty_slot = i; empty = slot;
} else if (slot->table->id == table->id) { } else if (slot->table_id == table_id) {
/* Already exists in our optimize queue. */ /* Already exists in our optimize queue. */
ut_ad(slot->table_id = table->id);
return(FALSE); return(FALSE);
} }
} }
/* Reuse old slot. */ slot = empty ? empty : static_cast<fts_slot_t*>(
if (empty_slot != ULINT_UNDEFINED) { ib_vector_push(fts_slots, NULL));
slot = static_cast<fts_slot_t*>(
ib_vector_get(tables, empty_slot));
ut_a(slot->state == FTS_STATE_EMPTY);
} else { /* Create a new slot. */
slot = static_cast<fts_slot_t*>(ib_vector_push(tables, NULL));
}
memset(slot, 0x0, sizeof(*slot)); memset(slot, 0x0, sizeof(*slot));
slot->table = table;
slot->table_id = table->id; slot->table_id = table->id;
slot->state = FTS_STATE_LOADED; slot->running = false;
slot->interval_time = FTS_OPTIMIZE_INTERVAL_IN_SECS; slot->interval_time = FTS_OPTIMIZE_INTERVAL_IN_SECS;
return(TRUE); return(TRUE);
} }
/**********************************************************************//** /** Remove a table from fts_slots if it exists.
Remove the table from the vector if it exists. */ @param[in,out] table table to be removed from fts_slots */
static static bool fts_optimize_del_table(const dict_table_t* table)
ibool
fts_optimize_del_table(
/*===================*/
ib_vector_t* tables, /*!< in/out: vector of tables */
fts_msg_del_t* msg) /*!< in: table to delete */
{ {
ulint i; const table_id_t table_id = table->id;
dict_table_t* table = msg->table; ut_ad(table_id);
for (i = 0; i < ib_vector_size(tables); ++i) { for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) {
fts_slot_t* slot; fts_slot_t* slot;
slot = static_cast<fts_slot_t*>(ib_vector_get(tables, i)); slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
/* FIXME: Should we assert on this ? */
if (slot->state != FTS_STATE_EMPTY
&& slot->table->id == table->id) {
ut_print_timestamp(stderr); if (slot->table_id == table_id) {
fprintf(stderr, " InnoDB: FTS Optimize Removing " if (fts_enable_diag_print) {
"table %s\n", table->name); ib_logf(IB_LOG_LEVEL_INFO,
"FTS Optimize Removing table %s",
slot->table = NULL; table->name);
slot->state = FTS_STATE_EMPTY; }
slot->table_id = 0;
return(TRUE); return(TRUE);
} }
} }
...@@ -2734,14 +2707,9 @@ fts_optimize_del_table( ...@@ -2734,14 +2707,9 @@ fts_optimize_del_table(
} }
/**********************************************************************//** /**********************************************************************//**
Calculate how many of the registered tables need to be optimized. Calculate how many tables in fts_slots need to be optimized.
@return no. of tables to optimize */ @return no. of tables to optimize */
static static ulint fts_optimize_how_many()
ulint
fts_optimize_how_many(
/*==================*/
const ib_vector_t* tables) /*!< in: registered tables
vector*/
{ {
ulint i; ulint i;
ib_time_t delta; ib_time_t delta;
...@@ -2750,15 +2718,14 @@ fts_optimize_how_many( ...@@ -2750,15 +2718,14 @@ fts_optimize_how_many(
current_time = ut_time(); current_time = ut_time();
for (i = 0; i < ib_vector_size(tables); ++i) { for (i = 0; i < ib_vector_size(fts_slots); ++i) {
const fts_slot_t* slot; const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i));
slot = static_cast<const fts_slot_t*>( if (slot->table_id == 0) {
ib_vector_get_const(tables, i)); continue;
}
switch (slot->state) { if (!slot->running) {
case FTS_STATE_DONE:
case FTS_STATE_LOADED:
ut_a(slot->completed <= current_time); ut_a(slot->completed <= current_time);
delta = current_time - slot->completed; delta = current_time - slot->completed;
...@@ -2767,9 +2734,7 @@ fts_optimize_how_many( ...@@ -2767,9 +2734,7 @@ fts_optimize_how_many(
if (delta >= slot->interval_time) { if (delta >= slot->interval_time) {
++n_tables; ++n_tables;
} }
break; } else {
case FTS_STATE_RUNNING:
ut_a(slot->last_run <= current_time); ut_a(slot->last_run <= current_time);
delta = current_time - slot->last_run; delta = current_time - slot->last_run;
...@@ -2777,15 +2742,7 @@ fts_optimize_how_many( ...@@ -2777,15 +2742,7 @@ fts_optimize_how_many(
if (delta > slot->interval_time) { if (delta > slot->interval_time) {
++n_tables; ++n_tables;
} }
break;
/* Slots in a state other than the above
are ignored. */
case FTS_STATE_EMPTY:
case FTS_STATE_SUSPENDED:
break;
} }
} }
return(n_tables); return(n_tables);
...@@ -2794,12 +2751,7 @@ fts_optimize_how_many( ...@@ -2794,12 +2751,7 @@ fts_optimize_how_many(
/**********************************************************************//** /**********************************************************************//**
Check if the total memory used by all FTS table exceeds the maximum limit. Check if the total memory used by all FTS table exceeds the maximum limit.
@return true if a sync is needed, false otherwise */ @return true if a sync is needed, false otherwise */
static static bool fts_is_sync_needed()
bool
fts_is_sync_needed(
/*===============*/
const ib_vector_t* tables) /*!< in: registered tables
vector*/
{ {
ulint total_memory = 0; ulint total_memory = 0;
double time_diff = difftime(ut_time(), last_check_sync_time); double time_diff = difftime(ut_time(), last_check_sync_time);
...@@ -2810,17 +2762,26 @@ fts_is_sync_needed( ...@@ -2810,17 +2762,26 @@ fts_is_sync_needed(
last_check_sync_time = ut_time(); last_check_sync_time = ut_time();
for (ulint i = 0; i < ib_vector_size(tables); ++i) { for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) {
const fts_slot_t* slot; const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i));
slot = static_cast<const fts_slot_t*>( if (slot->table_id == 0) {
ib_vector_get_const(tables, i)); continue;
}
if (slot->state != FTS_STATE_EMPTY && slot->table dict_table_t* table = dict_table_open_on_id(
&& slot->table->fts) { slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
total_memory += slot->table->fts->cache->total_size; if (!table) {
continue;
} }
if (table->fts && table->fts->cache) {
total_memory += table->fts->cache->total_size;
}
dict_table_close(table, FALSE, FALSE);
if (total_memory > fts_max_total_cache_size) { if (total_memory > fts_max_total_cache_size) {
return(true); return(true);
} }
...@@ -2831,16 +2792,12 @@ fts_is_sync_needed( ...@@ -2831,16 +2792,12 @@ fts_is_sync_needed(
/** Sync fts cache of a table /** Sync fts cache of a table
@param[in] table_id table id */ @param[in] table_id table id */
void static void fts_optimize_sync_table(table_id_t table_id)
fts_optimize_sync_table(
table_id_t table_id)
{ {
dict_table_t* table = NULL; if (dict_table_t* table = dict_table_open_on_id(
table_id, FALSE, DICT_TABLE_OP_NORMAL)) {
table = dict_table_open_on_id(table_id, FALSE, DICT_TABLE_OP_NORMAL); if (fil_table_accessible(table)
&& table->fts && table->fts->cache) {
if (table) {
if (dict_table_has_fts_index(table) && table->fts->cache) {
fts_sync_table(table, true, false, false); fts_sync_table(table, true, false, false);
} }
...@@ -2858,7 +2815,6 @@ fts_optimize_thread( ...@@ -2858,7 +2815,6 @@ fts_optimize_thread(
void* arg) /*!< in: work queue*/ void* arg) /*!< in: work queue*/
{ {
mem_heap_t* heap; mem_heap_t* heap;
ib_vector_t* tables;
ib_alloc_t* heap_alloc; ib_alloc_t* heap_alloc;
ulint current = 0; ulint current = 0;
ibool done = FALSE; ibool done = FALSE;
...@@ -2873,7 +2829,7 @@ fts_optimize_thread( ...@@ -2873,7 +2829,7 @@ fts_optimize_thread(
heap = mem_heap_create(sizeof(dict_table_t*) * 64); heap = mem_heap_create(sizeof(dict_table_t*) * 64);
heap_alloc = ib_heap_allocator_create(heap); heap_alloc = ib_heap_allocator_create(heap);
tables = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4); fts_slots = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4);
while(!done && srv_shutdown_state == SRV_SHUTDOWN_NONE) { while(!done && srv_shutdown_state == SRV_SHUTDOWN_NONE) {
...@@ -2884,28 +2840,18 @@ fts_optimize_thread( ...@@ -2884,28 +2840,18 @@ fts_optimize_thread(
&& ib_wqueue_is_empty(wq) && ib_wqueue_is_empty(wq)
&& n_tables > 0 && n_tables > 0
&& n_optimize > 0) { && n_optimize > 0) {
fts_slot_t* slot = static_cast<fts_slot_t*>(
fts_slot_t* slot; ib_vector_get(fts_slots, current));
ut_a(ib_vector_size(tables) > 0);
slot = static_cast<fts_slot_t*>(
ib_vector_get(tables, current));
/* Handle the case of empty slots. */ /* Handle the case of empty slots. */
if (slot->state != FTS_STATE_EMPTY) { if (slot->table_id) {
slot->running = true;
slot->state = FTS_STATE_RUNNING;
fts_optimize_table_bk(slot); fts_optimize_table_bk(slot);
} }
++current;
/* Wrap around the counter. */ /* Wrap around the counter. */
if (current >= ib_vector_size(tables)) { if (++current >= ib_vector_size(fts_slots)) {
n_optimize = fts_optimize_how_many(tables); n_optimize = fts_optimize_how_many();
current = 0; current = 0;
} }
...@@ -2917,7 +2863,7 @@ fts_optimize_thread( ...@@ -2917,7 +2863,7 @@ fts_optimize_thread(
/* Timeout ? */ /* Timeout ? */
if (msg == NULL) { if (msg == NULL) {
if (fts_is_sync_needed(tables)) { if (fts_is_sync_needed()) {
fts_need_sync = true; fts_need_sync = true;
} }
...@@ -2933,7 +2879,6 @@ fts_optimize_thread( ...@@ -2933,7 +2879,6 @@ fts_optimize_thread(
case FTS_MSG_ADD_TABLE: case FTS_MSG_ADD_TABLE:
ut_a(!done); ut_a(!done);
if (fts_optimize_new_table( if (fts_optimize_new_table(
tables,
static_cast<dict_table_t*>( static_cast<dict_table_t*>(
msg->ptr))) { msg->ptr))) {
++n_tables; ++n_tables;
...@@ -2942,8 +2887,8 @@ fts_optimize_thread( ...@@ -2942,8 +2887,8 @@ fts_optimize_thread(
case FTS_MSG_DEL_TABLE: case FTS_MSG_DEL_TABLE:
if (fts_optimize_del_table( if (fts_optimize_del_table(
tables, static_cast<fts_msg_del_t*>( static_cast<fts_msg_del_t*>(
msg->ptr))) { msg->ptr)->table)) {
--n_tables; --n_tables;
} }
...@@ -2967,33 +2912,25 @@ fts_optimize_thread( ...@@ -2967,33 +2912,25 @@ fts_optimize_thread(
} }
mem_heap_free(msg->heap); mem_heap_free(msg->heap);
n_optimize = done ? 0 : fts_optimize_how_many();
if (!done) {
n_optimize = fts_optimize_how_many(tables);
} else {
n_optimize = 0;
}
} }
} }
/* Server is being shutdown, sync the data from FTS cache to disk /* Server is being shutdown, sync the data from FTS cache to disk
if needed */ if needed */
if (n_tables > 0) { if (n_tables > 0) {
ulint i; for (ulint i = 0; i < ib_vector_size(fts_slots); i++) {
fts_slot_t* slot = static_cast<fts_slot_t*>(
for (i = 0; i < ib_vector_size(tables); i++) { ib_vector_get(fts_slots, i));
fts_slot_t* slot;
slot = static_cast<fts_slot_t*>(
ib_vector_get(tables, i));
if (slot->state != FTS_STATE_EMPTY) { if (table_id_t table_id = slot->table_id) {
fts_optimize_sync_table(slot->table_id); fts_optimize_sync_table(table_id);
} }
} }
} }
ib_vector_free(tables); ib_vector_free(fts_slots);
fts_slots = NULL;
ib_logf(IB_LOG_LEVEL_INFO, "FTS optimize thread exiting."); ib_logf(IB_LOG_LEVEL_INFO, "FTS optimize thread exiting.");
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2018, MariaDB Corporation. Copyright (c) 2013, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -843,6 +843,18 @@ fil_op_log_parse_or_replay( ...@@ -843,6 +843,18 @@ fil_op_log_parse_or_replay(
only be parsed but not replayed */ only be parsed but not replayed */
ulint log_flags); /*!< in: redo log flags ulint log_flags); /*!< in: redo log flags
(stored in the page number parameter) */ (stored in the page number parameter) */
/** Determine whether a table can be accessed in operations that are
not (necessarily) protected by meta-data locks.
(Rollback would generally be protected, but rollback of
FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks
but only by InnoDB table locks, which may be broken by
lock_remove_all_on_table().)
@param[in] table persistent table
checked @return whether the table is accessible */
UNIV_INTERN bool fil_table_accessible(const dict_table_t* table)
MY_ATTRIBUTE((warn_unused_result, nonnull));
/** Delete a tablespace and associated .ibd file. /** Delete a tablespace and associated .ibd file.
@param[in] id tablespace identifier @param[in] id tablespace identifier
@param[in] drop_ahi whether to drop the adaptive hash index @param[in] drop_ahi whether to drop the adaptive hash index
......
...@@ -2819,6 +2819,29 @@ fil_close_tablespace( ...@@ -2819,6 +2819,29 @@ fil_close_tablespace(
return(err); return(err);
} }
/** Determine whether a table can be accessed in operations that are
not (necessarily) protected by meta-data locks.
(Rollback would generally be protected, but rollback of
FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks
but only by InnoDB table locks, which may be broken by
lock_remove_all_on_table().)
@param[in] table persistent table
checked @return whether the table is accessible */
UNIV_INTERN bool fil_table_accessible(const dict_table_t* table)
{
if (UNIV_UNLIKELY(!table->is_readable() || table->corrupted)) {
return(false);
}
if (fil_space_t* space = fil_space_acquire(table->space)) {
bool accessible = !space->is_stopping();
fil_space_release(space);
return(accessible);
} else {
return(false);
}
}
/** Delete a tablespace and associated .ibd file. /** Delete a tablespace and associated .ibd file.
@param[in] id tablespace identifier @param[in] id tablespace identifier
@param[in] drop_ahi whether to drop the adaptive hash index @param[in] drop_ahi whether to drop the adaptive hash index
......
...@@ -43,6 +43,9 @@ Completed 2011/7/10 Sunny and Jimmy Yang ...@@ -43,6 +43,9 @@ Completed 2011/7/10 Sunny and Jimmy Yang
/** The FTS optimize thread's work queue. */ /** The FTS optimize thread's work queue. */
static ib_wqueue_t* fts_optimize_wq; static ib_wqueue_t* fts_optimize_wq;
/** The FTS vector to store fts_slot_t */
static ib_vector_t* fts_slots;
/** Time to wait for a message. */ /** Time to wait for a message. */
static const ulint FTS_QUEUE_WAIT_IN_USECS = 5000000; static const ulint FTS_QUEUE_WAIT_IN_USECS = 5000000;
...@@ -58,15 +61,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64; ...@@ -58,15 +61,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64;
/** Last time we did check whether system need a sync */ /** Last time we did check whether system need a sync */
static ib_time_t last_check_sync_time; static ib_time_t last_check_sync_time;
/** State of a table within the optimization sub system. */
enum fts_state_t {
FTS_STATE_LOADED,
FTS_STATE_RUNNING,
FTS_STATE_SUSPENDED,
FTS_STATE_DONE,
FTS_STATE_EMPTY
};
/** FTS optimize thread message types. */ /** FTS optimize thread message types. */
enum fts_msg_type_t { enum fts_msg_type_t {
FTS_MSG_STOP, /*!< Stop optimizing and exit thread */ FTS_MSG_STOP, /*!< Stop optimizing and exit thread */
...@@ -175,11 +169,11 @@ struct fts_encode_t { ...@@ -175,11 +169,11 @@ struct fts_encode_t {
/** We use this information to determine when to start the optimize /** We use this information to determine when to start the optimize
cycle for a table. */ cycle for a table. */
struct fts_slot_t { struct fts_slot_t {
dict_table_t* table; /*!< Table to optimize */ /** table identifier, or 0 if the slot is empty */
table_id_t table_id;
table_id_t table_id; /*!< Table id */
fts_state_t state; /*!< State of this slot */ /** whether this slot is being processed */
bool running;
ulint added; /*!< Number of doc ids added since the ulint added; /*!< Number of doc ids added since the
last time this table was optimized */ last time this table was optimized */
...@@ -2404,31 +2398,35 @@ fts_optimize_table_bk( ...@@ -2404,31 +2398,35 @@ fts_optimize_table_bk(
fts_slot_t* slot) /*!< in: table to optimiza */ fts_slot_t* slot) /*!< in: table to optimiza */
{ {
dberr_t error; dberr_t error;
dict_table_t* table = slot->table;
fts_t* fts = table->fts;
/* Avoid optimizing tables that were optimized recently. */ /* Avoid optimizing tables that were optimized recently. */
if (slot->last_run > 0 if (slot->last_run > 0
&& (ut_time() - slot->last_run) < slot->interval_time) { && (ut_time() - slot->last_run) < slot->interval_time) {
return(DB_SUCCESS); return(DB_SUCCESS);
}
} else if (fts && fts->cache dict_table_t* table = dict_table_open_on_id(
&& fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) { slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (table && fil_table_accessible(table)
&& table->fts && table->fts->cache
&& table->fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) {
error = fts_optimize_table(table); error = fts_optimize_table(table);
slot->last_run = ut_time();
if (error == DB_SUCCESS) { if (error == DB_SUCCESS) {
slot->state = FTS_STATE_DONE; slot->running = false;
slot->last_run = 0; slot->completed = slot->last_run;
slot->completed = ut_time();
} }
} else { } else {
/* Note time this run completed. */
slot->last_run = ut_time();
error = DB_SUCCESS; error = DB_SUCCESS;
} }
/* Note time this run completed. */ dict_table_close(table, FALSE, FALSE);
slot->last_run = ut_time();
return(error); return(error);
} }
...@@ -2647,85 +2645,60 @@ fts_optimize_request_sync_table( ...@@ -2647,85 +2645,60 @@ fts_optimize_request_sync_table(
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); ib_wqueue_add(fts_optimize_wq, msg, msg->heap);
} }
/**********************************************************************//** /** Add a table to fts_slots if it doesn't already exist. */
Add the table to the vector if it doesn't already exist. */ static bool fts_optimize_new_table(dict_table_t* table)
static
ibool
fts_optimize_new_table(
/*===================*/
ib_vector_t* tables, /*!< in/out: vector of tables */
dict_table_t* table) /*!< in: table to add */
{ {
ulint i; ulint i;
fts_slot_t* slot; fts_slot_t* slot;
ulint empty_slot = ULINT_UNDEFINED; fts_slot_t* empty = NULL;
const table_id_t table_id = table->id;
ut_ad(table_id);
/* Search for duplicates, also find a free slot if one exists. */ /* Search for duplicates, also find a free slot if one exists. */
for (i = 0; i < ib_vector_size(tables); ++i) { for (i = 0; i < ib_vector_size(fts_slots); ++i) {
slot = static_cast<fts_slot_t*>( slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
ib_vector_get(tables, i));
if (slot->state == FTS_STATE_EMPTY) { if (!slot->table_id) {
empty_slot = i; empty = slot;
} else if (slot->table->id == table->id) { } else if (slot->table_id == table_id) {
/* Already exists in our optimize queue. */ /* Already exists in our optimize queue. */
ut_ad(slot->table_id = table->id);
return(FALSE); return(FALSE);
} }
} }
/* Reuse old slot. */ slot = empty ? empty : static_cast<fts_slot_t*>(
if (empty_slot != ULINT_UNDEFINED) { ib_vector_push(fts_slots, NULL));
slot = static_cast<fts_slot_t*>(
ib_vector_get(tables, empty_slot));
ut_a(slot->state == FTS_STATE_EMPTY);
} else { /* Create a new slot. */
slot = static_cast<fts_slot_t*>(ib_vector_push(tables, NULL));
}
memset(slot, 0x0, sizeof(*slot)); memset(slot, 0x0, sizeof(*slot));
slot->table = table;
slot->table_id = table->id; slot->table_id = table->id;
slot->state = FTS_STATE_LOADED; slot->running = false;
slot->interval_time = FTS_OPTIMIZE_INTERVAL_IN_SECS; slot->interval_time = FTS_OPTIMIZE_INTERVAL_IN_SECS;
return(TRUE); return(TRUE);
} }
/**********************************************************************//** /** Remove a table from fts_slots if it exists.
Remove the table from the vector if it exists. */ @param[in,out] table table to be removed from fts_slots */
static static bool fts_optimize_del_table(const dict_table_t* table)
ibool
fts_optimize_del_table(
/*===================*/
ib_vector_t* tables, /*!< in/out: vector of tables */
fts_msg_del_t* msg) /*!< in: table to delete */
{ {
ulint i; const table_id_t table_id = table->id;
dict_table_t* table = msg->table; ut_ad(table_id);
for (i = 0; i < ib_vector_size(tables); ++i) { for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) {
fts_slot_t* slot; fts_slot_t* slot;
slot = static_cast<fts_slot_t*>(ib_vector_get(tables, i)); slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
/* FIXME: Should we assert on this ? */
if (slot->state != FTS_STATE_EMPTY
&& slot->table->id == table->id) {
ut_print_timestamp(stderr); if (slot->table_id == table_id) {
fprintf(stderr, " InnoDB: FTS Optimize Removing " if (fts_enable_diag_print) {
"table %s\n", table->name); ib_logf(IB_LOG_LEVEL_INFO,
"FTS Optimize Removing table %s",
slot->table = NULL; table->name);
slot->state = FTS_STATE_EMPTY; }
slot->table_id = 0;
return(TRUE); return(TRUE);
} }
} }
...@@ -2734,14 +2707,9 @@ fts_optimize_del_table( ...@@ -2734,14 +2707,9 @@ fts_optimize_del_table(
} }
/**********************************************************************//** /**********************************************************************//**
Calculate how many of the registered tables need to be optimized. Calculate how many tables in fts_slots need to be optimized.
@return no. of tables to optimize */ @return no. of tables to optimize */
static static ulint fts_optimize_how_many()
ulint
fts_optimize_how_many(
/*==================*/
const ib_vector_t* tables) /*!< in: registered tables
vector*/
{ {
ulint i; ulint i;
ib_time_t delta; ib_time_t delta;
...@@ -2750,15 +2718,14 @@ fts_optimize_how_many( ...@@ -2750,15 +2718,14 @@ fts_optimize_how_many(
current_time = ut_time(); current_time = ut_time();
for (i = 0; i < ib_vector_size(tables); ++i) { for (i = 0; i < ib_vector_size(fts_slots); ++i) {
const fts_slot_t* slot; const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i));
slot = static_cast<const fts_slot_t*>( if (slot->table_id == 0) {
ib_vector_get_const(tables, i)); continue;
}
switch (slot->state) { if (!slot->running) {
case FTS_STATE_DONE:
case FTS_STATE_LOADED:
ut_a(slot->completed <= current_time); ut_a(slot->completed <= current_time);
delta = current_time - slot->completed; delta = current_time - slot->completed;
...@@ -2767,9 +2734,7 @@ fts_optimize_how_many( ...@@ -2767,9 +2734,7 @@ fts_optimize_how_many(
if (delta >= slot->interval_time) { if (delta >= slot->interval_time) {
++n_tables; ++n_tables;
} }
break; } else {
case FTS_STATE_RUNNING:
ut_a(slot->last_run <= current_time); ut_a(slot->last_run <= current_time);
delta = current_time - slot->last_run; delta = current_time - slot->last_run;
...@@ -2777,15 +2742,7 @@ fts_optimize_how_many( ...@@ -2777,15 +2742,7 @@ fts_optimize_how_many(
if (delta > slot->interval_time) { if (delta > slot->interval_time) {
++n_tables; ++n_tables;
} }
break;
/* Slots in a state other than the above
are ignored. */
case FTS_STATE_EMPTY:
case FTS_STATE_SUSPENDED:
break;
} }
} }
return(n_tables); return(n_tables);
...@@ -2794,12 +2751,7 @@ fts_optimize_how_many( ...@@ -2794,12 +2751,7 @@ fts_optimize_how_many(
/**********************************************************************//** /**********************************************************************//**
Check if the total memory used by all FTS table exceeds the maximum limit. Check if the total memory used by all FTS table exceeds the maximum limit.
@return true if a sync is needed, false otherwise */ @return true if a sync is needed, false otherwise */
static static bool fts_is_sync_needed()
bool
fts_is_sync_needed(
/*===============*/
const ib_vector_t* tables) /*!< in: registered tables
vector*/
{ {
ulint total_memory = 0; ulint total_memory = 0;
double time_diff = difftime(ut_time(), last_check_sync_time); double time_diff = difftime(ut_time(), last_check_sync_time);
...@@ -2810,17 +2762,26 @@ fts_is_sync_needed( ...@@ -2810,17 +2762,26 @@ fts_is_sync_needed(
last_check_sync_time = ut_time(); last_check_sync_time = ut_time();
for (ulint i = 0; i < ib_vector_size(tables); ++i) { for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) {
const fts_slot_t* slot; const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i));
slot = static_cast<const fts_slot_t*>( if (slot->table_id == 0) {
ib_vector_get_const(tables, i)); continue;
}
if (slot->state != FTS_STATE_EMPTY && slot->table dict_table_t* table = dict_table_open_on_id(
&& slot->table->fts) { slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
total_memory += slot->table->fts->cache->total_size; if (!table) {
continue;
} }
if (table->fts && table->fts->cache) {
total_memory += table->fts->cache->total_size;
}
dict_table_close(table, FALSE, FALSE);
if (total_memory > fts_max_total_cache_size) { if (total_memory > fts_max_total_cache_size) {
return(true); return(true);
} }
...@@ -2831,16 +2792,12 @@ fts_is_sync_needed( ...@@ -2831,16 +2792,12 @@ fts_is_sync_needed(
/** Sync fts cache of a table /** Sync fts cache of a table
@param[in] table_id table id */ @param[in] table_id table id */
void static void fts_optimize_sync_table(table_id_t table_id)
fts_optimize_sync_table(
table_id_t table_id)
{ {
dict_table_t* table = NULL; if (dict_table_t* table = dict_table_open_on_id(
table_id, FALSE, DICT_TABLE_OP_NORMAL)) {
table = dict_table_open_on_id(table_id, FALSE, DICT_TABLE_OP_NORMAL); if (fil_table_accessible(table)
&& table->fts && table->fts->cache) {
if (table) {
if (dict_table_has_fts_index(table) && table->fts->cache) {
fts_sync_table(table, true, false, false); fts_sync_table(table, true, false, false);
} }
...@@ -2858,7 +2815,6 @@ fts_optimize_thread( ...@@ -2858,7 +2815,6 @@ fts_optimize_thread(
void* arg) /*!< in: work queue*/ void* arg) /*!< in: work queue*/
{ {
mem_heap_t* heap; mem_heap_t* heap;
ib_vector_t* tables;
ib_alloc_t* heap_alloc; ib_alloc_t* heap_alloc;
ulint current = 0; ulint current = 0;
ibool done = FALSE; ibool done = FALSE;
...@@ -2873,7 +2829,7 @@ fts_optimize_thread( ...@@ -2873,7 +2829,7 @@ fts_optimize_thread(
heap = mem_heap_create(sizeof(dict_table_t*) * 64); heap = mem_heap_create(sizeof(dict_table_t*) * 64);
heap_alloc = ib_heap_allocator_create(heap); heap_alloc = ib_heap_allocator_create(heap);
tables = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4); fts_slots = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4);
while(!done && srv_shutdown_state == SRV_SHUTDOWN_NONE) { while(!done && srv_shutdown_state == SRV_SHUTDOWN_NONE) {
...@@ -2884,28 +2840,18 @@ fts_optimize_thread( ...@@ -2884,28 +2840,18 @@ fts_optimize_thread(
&& ib_wqueue_is_empty(wq) && ib_wqueue_is_empty(wq)
&& n_tables > 0 && n_tables > 0
&& n_optimize > 0) { && n_optimize > 0) {
fts_slot_t* slot = static_cast<fts_slot_t*>(
fts_slot_t* slot; ib_vector_get(fts_slots, current));
ut_a(ib_vector_size(tables) > 0);
slot = static_cast<fts_slot_t*>(
ib_vector_get(tables, current));
/* Handle the case of empty slots. */ /* Handle the case of empty slots. */
if (slot->state != FTS_STATE_EMPTY) { if (slot->table_id) {
slot->running = true;
slot->state = FTS_STATE_RUNNING;
fts_optimize_table_bk(slot); fts_optimize_table_bk(slot);
} }
++current;
/* Wrap around the counter. */ /* Wrap around the counter. */
if (current >= ib_vector_size(tables)) { if (++current >= ib_vector_size(fts_slots)) {
n_optimize = fts_optimize_how_many(tables); n_optimize = fts_optimize_how_many();
current = 0; current = 0;
} }
...@@ -2917,7 +2863,7 @@ fts_optimize_thread( ...@@ -2917,7 +2863,7 @@ fts_optimize_thread(
/* Timeout ? */ /* Timeout ? */
if (msg == NULL) { if (msg == NULL) {
if (fts_is_sync_needed(tables)) { if (fts_is_sync_needed()) {
fts_need_sync = true; fts_need_sync = true;
} }
...@@ -2933,7 +2879,6 @@ fts_optimize_thread( ...@@ -2933,7 +2879,6 @@ fts_optimize_thread(
case FTS_MSG_ADD_TABLE: case FTS_MSG_ADD_TABLE:
ut_a(!done); ut_a(!done);
if (fts_optimize_new_table( if (fts_optimize_new_table(
tables,
static_cast<dict_table_t*>( static_cast<dict_table_t*>(
msg->ptr))) { msg->ptr))) {
++n_tables; ++n_tables;
...@@ -2942,8 +2887,8 @@ fts_optimize_thread( ...@@ -2942,8 +2887,8 @@ fts_optimize_thread(
case FTS_MSG_DEL_TABLE: case FTS_MSG_DEL_TABLE:
if (fts_optimize_del_table( if (fts_optimize_del_table(
tables, static_cast<fts_msg_del_t*>( static_cast<fts_msg_del_t*>(
msg->ptr))) { msg->ptr)->table)) {
--n_tables; --n_tables;
} }
...@@ -2967,33 +2912,25 @@ fts_optimize_thread( ...@@ -2967,33 +2912,25 @@ fts_optimize_thread(
} }
mem_heap_free(msg->heap); mem_heap_free(msg->heap);
n_optimize = done ? 0 : fts_optimize_how_many();
if (!done) {
n_optimize = fts_optimize_how_many(tables);
} else {
n_optimize = 0;
}
} }
} }
/* Server is being shutdown, sync the data from FTS cache to disk /* Server is being shutdown, sync the data from FTS cache to disk
if needed */ if needed */
if (n_tables > 0) { if (n_tables > 0) {
ulint i; for (ulint i = 0; i < ib_vector_size(fts_slots); i++) {
fts_slot_t* slot = static_cast<fts_slot_t*>(
for (i = 0; i < ib_vector_size(tables); i++) { ib_vector_get(fts_slots, i));
fts_slot_t* slot;
slot = static_cast<fts_slot_t*>(
ib_vector_get(tables, i));
if (slot->state != FTS_STATE_EMPTY) { if (table_id_t table_id = slot->table_id) {
fts_optimize_sync_table(slot->table_id); fts_optimize_sync_table(table_id);
} }
} }
} }
ib_vector_free(tables); ib_vector_free(fts_slots);
fts_slots = NULL;
ib_logf(IB_LOG_LEVEL_INFO, "FTS optimize thread exiting."); ib_logf(IB_LOG_LEVEL_INFO, "FTS optimize thread exiting.");
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2018, MariaDB Corporation. Copyright (c) 2013, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -841,6 +841,18 @@ fil_op_log_parse_or_replay( ...@@ -841,6 +841,18 @@ fil_op_log_parse_or_replay(
only be parsed but not replayed */ only be parsed but not replayed */
ulint log_flags); /*!< in: redo log flags ulint log_flags); /*!< in: redo log flags
(stored in the page number parameter) */ (stored in the page number parameter) */
/** Determine whether a table can be accessed in operations that are
not (necessarily) protected by meta-data locks.
(Rollback would generally be protected, but rollback of
FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks
but only by InnoDB table locks, which may be broken by
lock_remove_all_on_table().)
@param[in] table persistent table
checked @return whether the table is accessible */
UNIV_INTERN bool fil_table_accessible(const dict_table_t* table)
MY_ATTRIBUTE((warn_unused_result, nonnull));
/** Delete a tablespace and associated .ibd file. /** Delete a tablespace and associated .ibd file.
@param[in] id tablespace identifier @param[in] id tablespace identifier
@param[in] drop_ahi whether to drop the adaptive hash index @param[in] drop_ahi whether to drop the adaptive hash index
......
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