Commit d752a97e authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.1 to 10.2

parents 19ceaf29 a41d4297
...@@ -41,9 +41,11 @@ INSERT INTO articles (title,body) VALUES ...@@ -41,9 +41,11 @@ INSERT INTO articles (title,body) VALUES
('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
('MySQL vs. YourSQL','In the following database comparison ...'), ('MySQL vs. YourSQL','In the following database comparison ...'),
('MySQL Security','When configured properly, MySQL ...'); ('MySQL Security','When configured properly, MySQL ...');
connect dml, localhost, root,,;
BEGIN; BEGIN;
INSERT INTO articles (title,body) VALUES INSERT INTO articles (title,body) VALUES
('MySQL Tutorial','DBMS stands for DataBase ...'); ('MySQL Tutorial','DBMS stands for DataBase ...');
connection default;
# Make durable the AUTO_INCREMENT in the above incomplete transaction. # Make durable the AUTO_INCREMENT in the above incomplete transaction.
connect flush_redo_log,localhost,root,,; connect flush_redo_log,localhost,root,,;
SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL innodb_flush_log_at_trx_commit=1;
...@@ -52,6 +54,7 @@ DELETE FROM articles LIMIT 1; ...@@ -52,6 +54,7 @@ DELETE FROM articles LIMIT 1;
ROLLBACK; ROLLBACK;
disconnect flush_redo_log; disconnect flush_redo_log;
connection default; connection default;
disconnect dml;
INSERT INTO articles (title,body) VALUES INSERT INTO articles (title,body) VALUES
('MySQL Tutorial','DBMS stands for DataBase ...'); ('MySQL Tutorial','DBMS stands for DataBase ...');
SELECT * FROM articles SELECT * FROM articles
...@@ -79,9 +82,39 @@ INSERT INTO articles VALUES ...@@ -79,9 +82,39 @@ INSERT INTO articles VALUES
(4, 11, '1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), (4, 11, '1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
(5, 6, 'MySQL vs. YourSQL','In the following database comparison ...'), (5, 6, 'MySQL vs. YourSQL','In the following database comparison ...'),
(7, 4, 'MySQL Security','When configured properly, MySQL ...'); (7, 4, 'MySQL Security','When configured properly, MySQL ...');
connect dml, localhost, root,,;
BEGIN; BEGIN;
INSERT INTO articles VALUES INSERT INTO articles VALUES
(100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...'); (100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...');
connect dml2, localhost, root,,;
#
# MDEV-19073 FTS row mismatch after crash recovery
#
CREATE TABLE mdev19073(id SERIAL, title VARCHAR(200), body TEXT,
FULLTEXT(title,body)) ENGINE=InnoDB;
INSERT INTO mdev19073 (title, body) VALUES
('MySQL Tutorial', 'DBMS stands for Database...');
CREATE FULLTEXT INDEX idx ON mdev19073(title, body);
CREATE TABLE mdev19073_2 LIKE mdev19073;
INSERT INTO mdev19073_2 (title, body) VALUES
('MySQL Tutorial', 'DBMS stands for Database...');
INSERT INTO mdev19073 (title, body) VALUES
('MariaDB Tutorial', 'DB means Database ...');
INSERT INTO mdev19073_2 (title, body) VALUES
('MariaDB Tutorial', 'DB means Database ...');
SELECT * FROM mdev19073 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
id title body
1 MySQL Tutorial DBMS stands for Database...
2 MariaDB Tutorial DB means Database ...
SELECT * FROM mdev19073_2 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
id title body
1 MySQL Tutorial DBMS stands for Database...
2 MariaDB Tutorial DB means Database ...
connection default;
disconnect dml;
disconnect dml2;
INSERT INTO articles VALUES (8, 12, 'MySQL Tutorial','DBMS stands for DataBase ...'); INSERT INTO articles VALUES (8, 12, 'MySQL Tutorial','DBMS stands for DataBase ...');
SELECT * FROM articles WHERE MATCH (title, body) SELECT * FROM articles WHERE MATCH (title, body)
AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE);
...@@ -90,3 +123,14 @@ id FTS_DOC_ID title body ...@@ -90,3 +123,14 @@ id FTS_DOC_ID title body
1 10 MySQL Tutorial DBMS stands for DataBase ... 1 10 MySQL Tutorial DBMS stands for DataBase ...
8 12 MySQL Tutorial DBMS stands for DataBase ... 8 12 MySQL Tutorial DBMS stands for DataBase ...
DROP TABLE articles; DROP TABLE articles;
SELECT * FROM mdev19073 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
id title body
1 MySQL Tutorial DBMS stands for Database...
2 MariaDB Tutorial DB means Database ...
SELECT * FROM mdev19073_2 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
id title body
1 MySQL Tutorial DBMS stands for Database...
2 MariaDB Tutorial DB means Database ...
DROP TABLE mdev19073, mdev19073_2;
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
--source include/have_innodb.inc --source include/have_innodb.inc
# The embedded server tests do not support restarting. # The embedded server tests do not support restarting.
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/maybe_debug.inc
FLUSH TABLES; FLUSH TABLES;
# Following are test for crash recovery on FTS index, the first scenario # Following are test for crash recovery on FTS index, the first scenario
...@@ -73,10 +74,12 @@ INSERT INTO articles (title,body) VALUES ...@@ -73,10 +74,12 @@ INSERT INTO articles (title,body) VALUES
('MySQL vs. YourSQL','In the following database comparison ...'), ('MySQL vs. YourSQL','In the following database comparison ...'),
('MySQL Security','When configured properly, MySQL ...'); ('MySQL Security','When configured properly, MySQL ...');
connect(dml, localhost, root,,);
BEGIN; BEGIN;
INSERT INTO articles (title,body) VALUES INSERT INTO articles (title,body) VALUES
('MySQL Tutorial','DBMS stands for DataBase ...'); ('MySQL Tutorial','DBMS stands for DataBase ...');
connection default;
--echo # Make durable the AUTO_INCREMENT in the above incomplete transaction. --echo # Make durable the AUTO_INCREMENT in the above incomplete transaction.
--connect (flush_redo_log,localhost,root,,) --connect (flush_redo_log,localhost,root,,)
...@@ -89,6 +92,8 @@ ROLLBACK; ...@@ -89,6 +92,8 @@ ROLLBACK;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc
disconnect dml;
# This insert will re-initialize the Doc ID counter, it should not crash # This insert will re-initialize the Doc ID counter, it should not crash
INSERT INTO articles (title,body) VALUES INSERT INTO articles (title,body) VALUES
('MySQL Tutorial','DBMS stands for DataBase ...'); ('MySQL Tutorial','DBMS stands for DataBase ...');
...@@ -121,6 +126,7 @@ INSERT INTO articles VALUES ...@@ -121,6 +126,7 @@ INSERT INTO articles VALUES
(5, 6, 'MySQL vs. YourSQL','In the following database comparison ...'), (5, 6, 'MySQL vs. YourSQL','In the following database comparison ...'),
(7, 4, 'MySQL Security','When configured properly, MySQL ...'); (7, 4, 'MySQL Security','When configured properly, MySQL ...');
connect(dml, localhost, root,,);
BEGIN; BEGIN;
# Below we do not depend on the durability of the AUTO_INCREMENT sequence, # Below we do not depend on the durability of the AUTO_INCREMENT sequence,
...@@ -128,7 +134,49 @@ BEGIN; ...@@ -128,7 +134,49 @@ BEGIN;
INSERT INTO articles VALUES INSERT INTO articles VALUES
(100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...'); (100, 200, 'MySQL Tutorial','DBMS stands for DataBase ...');
connect(dml2, localhost, root,,);
--echo #
--echo # MDEV-19073 FTS row mismatch after crash recovery
--echo #
CREATE TABLE mdev19073(id SERIAL, title VARCHAR(200), body TEXT,
FULLTEXT(title,body)) ENGINE=InnoDB;
INSERT INTO mdev19073 (title, body) VALUES
('MySQL Tutorial', 'DBMS stands for Database...');
CREATE FULLTEXT INDEX idx ON mdev19073(title, body);
CREATE TABLE mdev19073_2 LIKE mdev19073;
if ($have_debug)
{
--disable_query_log
SET @saved_dbug = @@debug_dbug;
SET DEBUG_DBUG = '+d,fts_instrument_sync_debug';
--enable_query_log
}
INSERT INTO mdev19073_2 (title, body) VALUES
('MySQL Tutorial', 'DBMS stands for Database...');
if ($have_debug)
{
--disable_query_log
SET DEBUG_DBUG = @saved_dbug;
--enable_query_log
}
INSERT INTO mdev19073 (title, body) VALUES
('MariaDB Tutorial', 'DB means Database ...');
INSERT INTO mdev19073_2 (title, body) VALUES
('MariaDB Tutorial', 'DB means Database ...');
# Should return 2 rows
SELECT * FROM mdev19073 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
SELECT * FROM mdev19073_2 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
connection default;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc
disconnect dml;
disconnect dml2;
# This would re-initialize the FTS index and do the re-tokenization # This would re-initialize the FTS index and do the re-tokenization
# of above records # of above records
...@@ -138,3 +186,10 @@ SELECT * FROM articles WHERE MATCH (title, body) ...@@ -138,3 +186,10 @@ SELECT * FROM articles WHERE MATCH (title, body)
AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE);
DROP TABLE articles; DROP TABLE articles;
# Should return 2 rows
SELECT * FROM mdev19073 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
SELECT * FROM mdev19073_2 WHERE MATCH (title, body)
AGAINST ('Database' IN NATURAL LANGUAGE MODE);
DROP TABLE mdev19073, mdev19073_2;
...@@ -43,8 +43,7 @@ Created 4/24/1996 Heikki Tuuri ...@@ -43,8 +43,7 @@ Created 4/24/1996 Heikki Tuuri
#include "rem0cmp.h" #include "rem0cmp.h"
#include "srv0start.h" #include "srv0start.h"
#include "srv0srv.h" #include "srv0srv.h"
#include <stack> #include "fts0opt.h"
#include <set>
/** Following are the InnoDB system tables. The positions in /** Following are the InnoDB system tables. The positions in
this array are referenced by enum dict_system_table_id. */ this array are referenced by enum dict_system_table_id. */
...@@ -3121,8 +3120,12 @@ dict_load_table_one( ...@@ -3121,8 +3120,12 @@ dict_load_table_one(
FTS */ FTS */
fts_optimize_remove_table(table); fts_optimize_remove_table(table);
fts_free(table); fts_free(table);
} else { } else if (fts_optimize_wq) {
fts_optimize_add_table(table); fts_optimize_add_table(table);
} else {
/* fts_optimize_thread is not started yet.
So make the table as non-evictable from cache. */
dict_table_move_from_lru_to_non_lru(table);
} }
} }
......
...@@ -2712,6 +2712,10 @@ fts_cmp_set_sync_doc_id( ...@@ -2712,6 +2712,10 @@ fts_cmp_set_sync_doc_id(
} }
if (read_only) { if (read_only) {
/* InnoDB stores actual synced_doc_id value + 1 in
FTS_CONFIG table. Reduce the value by 1 while reading
after startup. */
if (*doc_id) *doc_id -= 1;
goto func_exit; goto func_exit;
} }
...@@ -5388,11 +5392,11 @@ fts_t::fts_t( ...@@ -5388,11 +5392,11 @@ fts_t::fts_t(
const dict_table_t* table, const dict_table_t* table,
mem_heap_t* heap) mem_heap_t* heap)
: :
in_queue(0), added_synced(0), dict_locked(0), added_synced(0), dict_locked(0),
bg_threads(0), bg_threads(0),
add_wq(NULL), add_wq(NULL),
cache(NULL), cache(NULL),
doc_col(ULINT_UNDEFINED), doc_col(ULINT_UNDEFINED), in_queue(false),
fts_heap(heap) fts_heap(heap)
{ {
ut_a(table->fts == NULL); ut_a(table->fts == NULL);
......
...@@ -35,9 +35,10 @@ Completed 2011/7/10 Sunny and Jimmy Yang ...@@ -35,9 +35,10 @@ Completed 2011/7/10 Sunny and Jimmy Yang
#include "srv0start.h" #include "srv0start.h"
#include "ut0list.h" #include "ut0list.h"
#include "zlib.h" #include "zlib.h"
#include "fts0opt.h"
/** The FTS optimize thread's work queue. */ /** The FTS optimize thread's work queue. */
static ib_wqueue_t* fts_optimize_wq; ib_wqueue_t* fts_optimize_wq;
/** The FTS vector to store fts_slot_t */ /** The FTS vector to store fts_slot_t */
static ib_vector_t* fts_slots; static ib_vector_t* fts_slots;
...@@ -168,8 +169,8 @@ struct fts_encode_t { ...@@ -168,8 +169,8 @@ 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 {
/** table identifier, or 0 if the slot is empty */ /** table, or NULL if the slot is unused */
table_id_t table_id; dict_table_t* table;
/** whether this slot is being processed */ /** whether this slot is being processed */
bool running; bool running;
...@@ -2391,14 +2392,7 @@ fts_optimize_table_bk( ...@@ -2391,14 +2392,7 @@ fts_optimize_table_bk(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
dict_table_t* table = dict_table_open_on_id( dict_table_t* table = slot->table;
slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!table) {
slot->last_run = now;
return DB_SUCCESS;
}
dberr_t error; dberr_t error;
if (fil_table_accessible(table) if (fil_table_accessible(table)
...@@ -2418,8 +2412,6 @@ fts_optimize_table_bk( ...@@ -2418,8 +2412,6 @@ fts_optimize_table_bk(
error = DB_SUCCESS; error = DB_SUCCESS;
} }
dict_table_close(table, FALSE, FALSE);
return(error); return(error);
} }
/*********************************************************************//** /*********************************************************************//**
...@@ -2564,11 +2556,13 @@ void fts_optimize_add_table(dict_table_t* table) ...@@ -2564,11 +2556,13 @@ void fts_optimize_add_table(dict_table_t* table)
msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table); msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table);
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); mutex_enter(&fts_optimize_wq->mutex);
ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true; table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
mutex_exit(&fts_optimize_wq->mutex);
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -2595,12 +2589,10 @@ fts_optimize_remove_table( ...@@ -2595,12 +2589,10 @@ fts_optimize_remove_table(
return; return;
} }
fts_t* fts = table->fts; mutex_enter(&fts_optimize_wq->mutex);
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) { if (!table->fts->in_queue) {
mutex_exit(&fts_optimize_wq->mutex);
return; return;
} }
...@@ -2616,15 +2608,17 @@ fts_optimize_remove_table( ...@@ -2616,15 +2608,17 @@ fts_optimize_remove_table(
remove->event = event; remove->event = event;
msg->ptr = remove; msg->ptr = remove;
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true);
mutex_exit(&fts_optimize_wq->mutex);
os_event_wait(event); os_event_wait(event);
os_event_destroy(event); os_event_destroy(event);
mutex_enter(&fts->bg_threads_mutex); ut_d(mutex_enter(&fts_optimize_wq->mutex));
fts->in_queue = false; ut_ad(!table->fts->in_queue);
mutex_exit(&fts->bg_threads_mutex); ut_d(mutex_exit(&fts_optimize_wq->mutex));
} }
/** Send sync fts cache for the table. /** Send sync fts cache for the table.
...@@ -2633,9 +2627,6 @@ void ...@@ -2633,9 +2627,6 @@ void
fts_optimize_request_sync_table( fts_optimize_request_sync_table(
dict_table_t* table) dict_table_t* table)
{ {
fts_msg_t* msg;
table_id_t* table_id;
/* if the optimize system not yet initialized, return */ /* if the optimize system not yet initialized, return */
if (!fts_optimize_wq) { if (!fts_optimize_wq) {
return; return;
...@@ -2648,39 +2639,36 @@ fts_optimize_request_sync_table( ...@@ -2648,39 +2639,36 @@ fts_optimize_request_sync_table(
return; return;
} }
msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, NULL); fts_msg_t* msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, table);
table_id = static_cast<table_id_t*>( mutex_enter(&fts_optimize_wq->mutex);
mem_heap_alloc(msg->heap, sizeof(table_id_t)));
*table_id = table->id;
msg->ptr = table_id;
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true; table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
mutex_exit(&fts_optimize_wq->mutex);
} }
/** Add a table to fts_slots if it doesn't already exist. */ /** Add a table to fts_slots if it doesn't already exist. */
static bool fts_optimize_new_table(dict_table_t* table) static bool fts_optimize_new_table(dict_table_t* table)
{ {
ut_ad(table);
ulint i; ulint i;
fts_slot_t* slot; fts_slot_t* slot;
fts_slot_t* empty = NULL; 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(fts_slots); ++i) { for (i = 0; i < ib_vector_size(fts_slots); ++i) {
slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i)); slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
if (!slot->table_id) { if (!slot->table) {
empty = slot; empty = slot;
} else if (slot->table_id == table_id) { } else if (slot->table == table) {
/* Already exists in our optimize queue. */ /* Already exists in our optimize queue. */
return(FALSE); return false;
} }
} }
...@@ -2689,36 +2677,35 @@ static bool fts_optimize_new_table(dict_table_t* table) ...@@ -2689,36 +2677,35 @@ static bool fts_optimize_new_table(dict_table_t* table)
memset(slot, 0x0, sizeof(*slot)); memset(slot, 0x0, sizeof(*slot));
slot->table_id = table->id; slot->table = table;
slot->running = false; return true;
return(TRUE);
} }
/** Remove a table from fts_slots if it exists. /** Remove a table from fts_slots if it exists.
@param[in,out] table table to be removed from fts_slots */ @param[in,out] table table to be removed from fts_slots */
static bool fts_optimize_del_table(const dict_table_t* table) static bool fts_optimize_del_table(const dict_table_t* table)
{ {
const table_id_t table_id = table->id; ut_ad(table);
ut_ad(table_id);
for (ulint i = 0; i < ib_vector_size(fts_slots); ++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(fts_slots, i)); slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
if (slot->table_id == table_id) { if (slot->table == table) {
if (fts_enable_diag_print) { if (fts_enable_diag_print) {
ib::info() << "FTS Optimize Removing table " ib::info() << "FTS Optimize Removing table "
<< table->name; << table->name;
} }
slot->table_id = 0; mutex_enter(&fts_optimize_wq->mutex);
return(TRUE); slot->table->fts->in_queue = false;
mutex_exit(&fts_optimize_wq->mutex);
slot->table = NULL;
return true;
} }
} }
return(FALSE); return false;
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -2732,7 +2719,7 @@ static ulint fts_optimize_how_many() ...@@ -2732,7 +2719,7 @@ static ulint fts_optimize_how_many()
for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) {
const fts_slot_t* slot = static_cast<const fts_slot_t*>( const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i)); ib_vector_get_const(fts_slots, i));
if (slot->table_id == 0) { if (!slot->table) {
continue; continue;
} }
...@@ -2768,22 +2755,14 @@ static bool fts_is_sync_needed() ...@@ -2768,22 +2755,14 @@ static bool fts_is_sync_needed()
const fts_slot_t* slot = static_cast<const fts_slot_t*>( const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i)); ib_vector_get_const(fts_slots, i));
if (slot->table_id == 0) { if (!slot->table) {
continue;
}
dict_table_t* table = dict_table_open_on_id(
slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!table) {
continue; continue;
} }
if (table->fts && table->fts->cache) { if (slot->table->fts && slot->table->fts->cache) {
total_memory += table->fts->cache->total_size; total_memory += slot->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);
} }
...@@ -2793,22 +2772,14 @@ static bool fts_is_sync_needed() ...@@ -2793,22 +2772,14 @@ static bool fts_is_sync_needed()
} }
/** Sync fts cache of a table /** Sync fts cache of a table
@param[in] table_id table id */ @param[in,out] table table to be synced */
static void fts_optimize_sync_table(table_id_t table_id) static void fts_optimize_sync_table(dict_table_t* table)
{ {
if (dict_table_t* table = dict_table_open_on_id( if (table->fts && table->fts->cache && fil_table_accessible(table)) {
table_id, FALSE, DICT_TABLE_OP_NORMAL)) { fts_sync_table(table, false);
if (fil_table_accessible(table)
&& table->fts && table->fts->cache) {
fts_sync_table(table, false);
}
DBUG_EXECUTE_IF(
"ib_optimize_wq_hang",
os_thread_sleep(6000000););
dict_table_close(table, FALSE, FALSE);
} }
DBUG_EXECUTE_IF("ib_optimize_wq_hang", os_thread_sleep(6000000););
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -2847,7 +2818,7 @@ fts_optimize_thread( ...@@ -2847,7 +2818,7 @@ fts_optimize_thread(
ib_vector_get(fts_slots, current)); ib_vector_get(fts_slots, current));
/* Handle the case of empty slots. */ /* Handle the case of empty slots. */
if (slot->table_id) { if (slot->table) {
slot->running = true; slot->running = true;
fts_optimize_table_bk(slot); fts_optimize_table_bk(slot);
} }
...@@ -2906,7 +2877,7 @@ fts_optimize_thread( ...@@ -2906,7 +2877,7 @@ fts_optimize_thread(
os_thread_sleep(300000);); os_thread_sleep(300000););
fts_optimize_sync_table( fts_optimize_sync_table(
*static_cast<table_id_t*>(msg->ptr)); static_cast<dict_table_t*>(msg->ptr));
break; break;
default: default:
...@@ -2925,8 +2896,8 @@ fts_optimize_thread( ...@@ -2925,8 +2896,8 @@ fts_optimize_thread(
fts_slot_t* slot = static_cast<fts_slot_t*>( fts_slot_t* slot = static_cast<fts_slot_t*>(
ib_vector_get(fts_slots, i)); ib_vector_get(fts_slots, i));
if (table_id_t table_id = slot->table_id) { if (slot->table) {
fts_optimize_sync_table(table_id); fts_optimize_sync_table(slot->table);
} }
} }
} }
...@@ -2954,7 +2925,6 @@ fts_optimize_init(void) ...@@ -2954,7 +2925,6 @@ fts_optimize_init(void)
{ {
mem_heap_t* heap; mem_heap_t* heap;
ib_alloc_t* heap_alloc; ib_alloc_t* heap_alloc;
dict_table_t* table;
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
...@@ -2970,31 +2940,25 @@ fts_optimize_init(void) ...@@ -2970,31 +2940,25 @@ fts_optimize_init(void)
heap_alloc = ib_heap_allocator_create(heap); heap_alloc = ib_heap_allocator_create(heap);
fts_slots = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4); fts_slots = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4);
/* Add fts tables to the fts_slots vector which were skipped during restart */ /* Add fts tables to fts_slots which could be skipped
std::vector<dict_table_t*> table_vector; during dict_load_table_one() because fts_optimize_thread
std::vector<dict_table_t*>::iterator it; wasn't even started. */
mutex_enter(&dict_sys->mutex); mutex_enter(&dict_sys->mutex);
for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); for (dict_table_t* table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
table != NULL; table != NULL;
table = UT_LIST_GET_NEXT(table_LRU, table)) { table = UT_LIST_GET_NEXT(table_LRU, table)) {
if (table->fts && if (!table->fts || !dict_table_has_fts_index(table)) {
dict_table_has_fts_index(table)) { continue;
if (fts_optimize_new_table(table)){
table_vector.push_back(table);
}
} }
}
/* It is better to call dict_table_prevent_eviction() /* fts_optimize_thread is not started yet. So there is no
outside the above loop because it operates on need to acquire fts_optimize_wq->mutex for adding the fts
dict_sys->table_LRU list.*/ table to the fts slots. */
for (it=table_vector.begin();it!=table_vector.end();++it) { ut_ad(!table->can_be_evicted);
dict_table_prevent_eviction(*it); fts_optimize_new_table(table);
table->fts->in_queue = true;
} }
mutex_exit(&dict_sys->mutex); mutex_exit(&dict_sys->mutex);
table_vector.clear();
fts_opt_shutdown_event = os_event_create(0); fts_opt_shutdown_event = os_event_create(0);
last_check_sync_time = time(NULL); last_check_sync_time = time(NULL);
......
...@@ -320,9 +320,6 @@ class fts_t { ...@@ -320,9 +320,6 @@ class fts_t {
/** Mutex protecting bg_threads* and fts_add_wq. */ /** Mutex protecting bg_threads* and fts_add_wq. */
ib_mutex_t bg_threads_mutex; ib_mutex_t bg_threads_mutex;
/** 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 after /** Whether the ADDED table record sync-ed after
crash recovery; protected by bg_threads_mutex */ crash recovery; protected by bg_threads_mutex */
unsigned added_synced:1; unsigned added_synced:1;
...@@ -348,6 +345,10 @@ class fts_t { ...@@ -348,6 +345,10 @@ class fts_t {
/** Vector of FTS indexes, this is mainly for caching purposes. */ /** Vector of FTS indexes, this is mainly for caching purposes. */
ib_vector_t* indexes; ib_vector_t* indexes;
/** Whether the table exists in fts_optimize_wq;
protected by fts_optimize_wq mutex */
bool in_queue;
/** Heap for fts_t allocation. */ /** Heap for fts_t allocation. */
mem_heap_t* fts_heap; mem_heap_t* fts_heap;
}; };
......
...@@ -25,6 +25,9 @@ Created 2011-02-15 Jimmy Yang ...@@ -25,6 +25,9 @@ Created 2011-02-15 Jimmy Yang
#ifndef INNODB_FTS0OPT_H #ifndef INNODB_FTS0OPT_H
#define INNODB_FTS0OPT_H #define INNODB_FTS0OPT_H
/** The FTS optimize thread's work queue. */
extern ib_wqueue_t* fts_optimize_wq;
/******************************************************************** /********************************************************************
Callback function to fetch the rows in an FTS INDEX record. */ Callback function to fetch the rows in an FTS INDEX record. */
ibool ibool
......
...@@ -38,7 +38,18 @@ processing. ...@@ -38,7 +38,18 @@ processing.
// Forward declaration // Forward declaration
struct ib_list_t; struct ib_list_t;
struct ib_wqueue_t;
/** Work queue */
struct ib_wqueue_t
{
/** Mutex protecting everything */
ib_mutex_t mutex;
/** Work item list */
ib_list_t* items;
/** event we use to signal additions to list;
os_event_set() and os_event_reset() are protected by the mutex */
os_event_t event;
};
/****************************************************************//** /****************************************************************//**
Create a new work queue. Create a new work queue.
...@@ -54,15 +65,14 @@ ib_wqueue_free( ...@@ -54,15 +65,14 @@ ib_wqueue_free(
/*===========*/ /*===========*/
ib_wqueue_t* wq); /*!< in: work queue */ ib_wqueue_t* wq); /*!< in: work queue */
/****************************************************************//** /** Add a work item to the queue.
Add a work item to the queue. */ @param[in,out] wq work queue
@param[in] item work item
@param[in,out] heap memory heap to use for allocating list node
@param[in] wq_locked work queue mutex locked */
void void
ib_wqueue_add( ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap,
/*==========*/ bool wq_locked = false);
ib_wqueue_t* wq, /*!< in: work queue */
void* item, /*!< in: work item */
mem_heap_t* heap); /*!< in: memory heap to use for
allocating the list node */
/** Check if queue is empty. /** Check if queue is empty.
@param wq wait queue @param wq wait queue
...@@ -101,5 +111,4 @@ ib_wqueue_len( ...@@ -101,5 +111,4 @@ ib_wqueue_len(
/*==========*/ /*==========*/
ib_wqueue_t* wq); /*<! in: work queue */ ib_wqueue_t* wq); /*<! in: work queue */
#endif /* IB_WORK_QUEUE_H */ #endif /* IB_WORK_QUEUE_H */
...@@ -28,15 +28,6 @@ A work queue ...@@ -28,15 +28,6 @@ A work queue
Created 4/26/2006 Osku Salerma Created 4/26/2006 Osku Salerma
************************************************************************/ ************************************************************************/
/* Work queue. */
struct ib_wqueue_t {
ib_mutex_t mutex; /*!< mutex protecting everything */
ib_list_t* items; /*!< work item list */
os_event_t event; /*!< event we use to signal additions to list;
os_event_set() and os_event_reset() are
protected by ib_wqueue_t::mutex */
};
/****************************************************************//** /****************************************************************//**
Create a new work queue. Create a new work queue.
@return work queue */ @return work queue */
...@@ -72,22 +63,24 @@ ib_wqueue_free( ...@@ -72,22 +63,24 @@ ib_wqueue_free(
ut_free(wq); ut_free(wq);
} }
/****************************************************************//** /** Add a work item to the queue.
Add a work item to the queue. */ @param[in,out] wq work queue
@param[in] item work item
@param[in,out] heap memory heap to use for allocating list node
@param[in] wq_locked work queue mutex locked */
void void
ib_wqueue_add( ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, bool wq_locked)
/*==========*/
ib_wqueue_t* wq, /*!< in: work queue */
void* item, /*!< in: work item */
mem_heap_t* heap) /*!< in: memory heap to use for allocating the
list node */
{ {
mutex_enter(&wq->mutex); if (!wq_locked) {
mutex_enter(&wq->mutex);
}
ib_list_add_last(wq->items, item, heap); ib_list_add_last(wq->items, item, heap);
os_event_set(wq->event); os_event_set(wq->event);
mutex_exit(&wq->mutex); if (!wq_locked) {
mutex_exit(&wq->mutex);
}
} }
/****************************************************************//** /****************************************************************//**
......
...@@ -46,6 +46,7 @@ Created 4/24/1996 Heikki Tuuri ...@@ -46,6 +46,7 @@ Created 4/24/1996 Heikki Tuuri
#include "dict0priv.h" #include "dict0priv.h"
#include "ha_prototypes.h" /* innobase_casedn_str() */ #include "ha_prototypes.h" /* innobase_casedn_str() */
#include "fts0priv.h" #include "fts0priv.h"
#include "fts0opt.h"
/** Following are the InnoDB system tables. The positions in /** Following are the InnoDB system tables. The positions in
this array are referenced by enum dict_system_table_id. */ this array are referenced by enum dict_system_table_id. */
...@@ -2570,8 +2571,12 @@ dict_load_table( ...@@ -2570,8 +2571,12 @@ dict_load_table(
FTS */ FTS */
fts_optimize_remove_table(table); fts_optimize_remove_table(table);
fts_free(table); fts_free(table);
} else { } else if (fts_optimize_wq) {
fts_optimize_add_table(table); fts_optimize_add_table(table);
} else {
/* fts_optimize_thread is not started yet.
So make the table as non-evictable from cache. */
dict_table_move_from_lru_to_non_lru(table);
} }
} }
......
...@@ -2739,6 +2739,10 @@ fts_cmp_set_sync_doc_id( ...@@ -2739,6 +2739,10 @@ fts_cmp_set_sync_doc_id(
} }
if (read_only) { if (read_only) {
/* InnoDB stores actual synced_doc_id value + 1 in
FTS_CONFIG table. Reduce the value by 1 while reading
after startup. */
if (*doc_id) *doc_id -= 1;
goto func_exit; goto func_exit;
} }
......
...@@ -34,6 +34,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang ...@@ -34,6 +34,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang
#include "ut0wqueue.h" #include "ut0wqueue.h"
#include "srv0start.h" #include "srv0start.h"
#include "zlib.h" #include "zlib.h"
#include "fts0opt.h"
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "fts0types.ic" #include "fts0types.ic"
...@@ -41,7 +42,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang ...@@ -41,7 +42,7 @@ Completed 2011/7/10 Sunny and Jimmy Yang
#endif #endif
/** The FTS optimize thread's work queue. */ /** The FTS optimize thread's work queue. */
static ib_wqueue_t* fts_optimize_wq; ib_wqueue_t* fts_optimize_wq;
/** The FTS vector to store fts_slot_t */ /** The FTS vector to store fts_slot_t */
static ib_vector_t* fts_slots; static ib_vector_t* fts_slots;
...@@ -169,8 +170,8 @@ struct fts_encode_t { ...@@ -169,8 +170,8 @@ 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 {
/** table identifier, or 0 if the slot is empty */ /** table, or NULL if the slot is unused */
table_id_t table_id; dict_table_t* table;
/** whether this slot is being processed */ /** whether this slot is being processed */
bool running; bool running;
...@@ -2456,14 +2457,7 @@ fts_optimize_table_bk( ...@@ -2456,14 +2457,7 @@ fts_optimize_table_bk(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
dict_table_t* table = dict_table_open_on_id( dict_table_t* table = slot->table;
slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!table) {
slot->last_run = now;
return DB_SUCCESS;
}
dberr_t error; dberr_t error;
if (fil_table_accessible(table) if (fil_table_accessible(table)
...@@ -2483,8 +2477,6 @@ fts_optimize_table_bk( ...@@ -2483,8 +2477,6 @@ fts_optimize_table_bk(
error = DB_SUCCESS; error = DB_SUCCESS;
} }
dict_table_close(table, FALSE, FALSE);
return(error); return(error);
} }
/*********************************************************************//** /*********************************************************************//**
...@@ -2627,11 +2619,13 @@ UNIV_INTERN void fts_optimize_add_table(dict_table_t* table) ...@@ -2627,11 +2619,13 @@ UNIV_INTERN void fts_optimize_add_table(dict_table_t* table)
msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table); msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table);
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); mutex_enter(&fts_optimize_wq->mutex);
ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true; table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
mutex_exit(&fts_optimize_wq->mutex);
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -2648,7 +2642,7 @@ fts_optimize_remove_table( ...@@ -2648,7 +2642,7 @@ fts_optimize_remove_table(
fts_msg_del_t* remove; fts_msg_del_t* remove;
/* if the optimize system not yet initialized, return */ /* if the optimize system not yet initialized, return */
if (!fts_optimize_is_init()) { if (!fts_optimize_wq) {
return; return;
} }
...@@ -2660,12 +2654,10 @@ fts_optimize_remove_table( ...@@ -2660,12 +2654,10 @@ fts_optimize_remove_table(
return; return;
} }
fts_t* fts = table->fts; mutex_enter(&fts_optimize_wq->mutex);
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) { if (!table->fts->in_queue) {
mutex_exit(&fts_optimize_wq->mutex);
return; return;
} }
...@@ -2681,15 +2673,17 @@ fts_optimize_remove_table( ...@@ -2681,15 +2673,17 @@ fts_optimize_remove_table(
remove->event = event; remove->event = event;
msg->ptr = remove; msg->ptr = remove;
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true);
mutex_exit(&fts_optimize_wq->mutex);
os_event_wait(event); os_event_wait(event);
os_event_free(event); os_event_free(event);
mutex_enter(&fts->bg_threads_mutex); ut_d(mutex_enter(&fts_optimize_wq->mutex));
fts->in_queue = false; ut_ad(!table->fts->in_queue);
mutex_exit(&fts->bg_threads_mutex); ut_d(mutex_exit(&fts_optimize_wq->mutex));
} }
/** Send sync fts cache for the table. /** Send sync fts cache for the table.
...@@ -2700,10 +2694,9 @@ fts_optimize_request_sync_table( ...@@ -2700,10 +2694,9 @@ fts_optimize_request_sync_table(
dict_table_t* table) dict_table_t* table)
{ {
fts_msg_t* msg; fts_msg_t* msg;
table_id_t* table_id;
/* if the optimize system not yet initialized, return */ /* if the optimize system not yet initialized, return */
if (!fts_optimize_is_init()) { if (!fts_optimize_wq) {
return; return;
} }
...@@ -2715,39 +2708,36 @@ fts_optimize_request_sync_table( ...@@ -2715,39 +2708,36 @@ fts_optimize_request_sync_table(
return; return;
} }
msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, NULL); msg = fts_optimize_create_msg(FTS_MSG_SYNC_TABLE, table);
table_id = static_cast<table_id_t*>( mutex_enter(&fts_optimize_wq->mutex);
mem_heap_alloc(msg->heap, sizeof(table_id_t)));
*table_id = table->id;
msg->ptr = table_id;
ib_wqueue_add(fts_optimize_wq, msg, msg->heap); ib_wqueue_add(fts_optimize_wq, msg, msg->heap, true);
mutex_enter(&table->fts->bg_threads_mutex);
table->fts->in_queue = true; table->fts->in_queue = true;
mutex_exit(&table->fts->bg_threads_mutex);
mutex_exit(&fts_optimize_wq->mutex);
} }
/** Add a table to fts_slots if it doesn't already exist. */ /** Add a table to fts_slots if it doesn't already exist. */
static bool fts_optimize_new_table(dict_table_t* table) static bool fts_optimize_new_table(dict_table_t* table)
{ {
ut_ad(table);
ulint i; ulint i;
fts_slot_t* slot; fts_slot_t* slot;
fts_slot_t* empty = NULL; 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(fts_slots); ++i) { for (i = 0; i < ib_vector_size(fts_slots); ++i) {
slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i)); slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
if (!slot->table_id) { if (!slot->table) {
empty = slot; empty = slot;
} else if (slot->table_id == table_id) { } else if (slot->table == table) {
/* Already exists in our optimize queue. */ /* Already exists in our optimize queue. */
return(FALSE); return false;
} }
} }
...@@ -2756,37 +2746,36 @@ static bool fts_optimize_new_table(dict_table_t* table) ...@@ -2756,37 +2746,36 @@ static bool fts_optimize_new_table(dict_table_t* table)
memset(slot, 0x0, sizeof(*slot)); memset(slot, 0x0, sizeof(*slot));
slot->table_id = table->id; slot->table = table;
slot->running = false; return true;
return(TRUE);
} }
/** Remove a table from fts_slots if it exists. /** Remove a table from fts_slots if it exists.
@param[in,out] table table to be removed from fts_slots */ @param[in,out] table table to be removed from fts_slots */
static bool fts_optimize_del_table(const dict_table_t* table) static bool fts_optimize_del_table(const dict_table_t* table)
{ {
const table_id_t table_id = table->id;
ut_ad(table_id);
for (ulint i = 0; i < ib_vector_size(fts_slots); ++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(fts_slots, i)); slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i));
if (slot->table_id == table_id) { if (slot->table == table) {
if (fts_enable_diag_print) { if (fts_enable_diag_print) {
ib_logf(IB_LOG_LEVEL_INFO, ib_logf(IB_LOG_LEVEL_INFO,
"FTS Optimize Removing table %s", "FTS Optimize Removing table %s",
table->name); table->name);
} }
slot->table_id = 0; mutex_enter(&fts_optimize_wq->mutex);
return(TRUE); slot->table->fts->in_queue = false;
mutex_exit(&fts_optimize_wq->mutex);
slot->table = NULL;
return true;
} }
} }
return(FALSE); return false;
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -2800,7 +2789,7 @@ static ulint fts_optimize_how_many() ...@@ -2800,7 +2789,7 @@ static ulint fts_optimize_how_many()
for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) {
const fts_slot_t* slot = static_cast<const fts_slot_t*>( const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i)); ib_vector_get_const(fts_slots, i));
if (slot->table_id == 0) { if (!slot->table) {
continue; continue;
} }
...@@ -2836,22 +2825,14 @@ static bool fts_is_sync_needed() ...@@ -2836,22 +2825,14 @@ static bool fts_is_sync_needed()
const fts_slot_t* slot = static_cast<const fts_slot_t*>( const fts_slot_t* slot = static_cast<const fts_slot_t*>(
ib_vector_get_const(fts_slots, i)); ib_vector_get_const(fts_slots, i));
if (slot->table_id == 0) { if (!slot->table) {
continue;
}
dict_table_t* table = dict_table_open_on_id(
slot->table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!table) {
continue; continue;
} }
if (table->fts && table->fts->cache) { if (slot->table->fts && slot->table->fts->cache) {
total_memory += table->fts->cache->total_size; total_memory += slot->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);
} }
...@@ -2861,22 +2842,16 @@ static bool fts_is_sync_needed() ...@@ -2861,22 +2842,16 @@ static bool fts_is_sync_needed()
} }
/** Sync fts cache of a table /** Sync fts cache of a table
@param[in] table_id table id */ @param[in,out] table table to be synced */
static void fts_optimize_sync_table(table_id_t table_id) static void fts_optimize_sync_table(dict_table_t* table)
{ {
if (dict_table_t* table = dict_table_open_on_id( if (fil_table_accessible(table)
table_id, FALSE, DICT_TABLE_OP_NORMAL)) { && table->fts && table->fts->cache) {
if (fil_table_accessible(table) fts_sync_table(table, true, false, false);
&& table->fts && table->fts->cache) { }
fts_sync_table(table, true, false, false);
}
DBUG_EXECUTE_IF( DBUG_EXECUTE_IF("ib_optimize_wq_hang",
"ib_optimize_wq_hang",
os_thread_sleep(6000000);); os_thread_sleep(6000000););
dict_table_close(table, FALSE, FALSE);
}
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -2918,7 +2893,7 @@ fts_optimize_thread( ...@@ -2918,7 +2893,7 @@ fts_optimize_thread(
ib_vector_get(fts_slots, current)); ib_vector_get(fts_slots, current));
/* Handle the case of empty slots. */ /* Handle the case of empty slots. */
if (slot->table_id) { if (slot->table) {
slot->running = true; slot->running = true;
fts_optimize_table_bk(slot); fts_optimize_table_bk(slot);
} }
...@@ -2978,7 +2953,7 @@ fts_optimize_thread( ...@@ -2978,7 +2953,7 @@ fts_optimize_thread(
os_thread_sleep(300000);); os_thread_sleep(300000););
fts_optimize_sync_table( fts_optimize_sync_table(
*static_cast<table_id_t*>(msg->ptr)); static_cast<dict_table_t*>(msg->ptr));
break; break;
default: default:
...@@ -2997,8 +2972,8 @@ fts_optimize_thread( ...@@ -2997,8 +2972,8 @@ fts_optimize_thread(
fts_slot_t* slot = static_cast<fts_slot_t*>( fts_slot_t* slot = static_cast<fts_slot_t*>(
ib_vector_get(fts_slots, i)); ib_vector_get(fts_slots, i));
if (table_id_t table_id = slot->table_id) { if (slot->table) {
fts_optimize_sync_table(table_id); fts_optimize_sync_table(slot->table);
} }
} }
} }
...@@ -3028,24 +3003,35 @@ fts_optimize_init(void) ...@@ -3028,24 +3003,35 @@ fts_optimize_init(void)
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
/* For now we only support one optimize thread. */ /* For now we only support one optimize thread. */
ut_a(!fts_optimize_is_init()); ut_a(!fts_optimize_wq);
fts_optimize_wq = ib_wqueue_create(); fts_optimize_wq = ib_wqueue_create();
ut_a(fts_optimize_wq != NULL); ut_a(fts_optimize_wq != NULL);
last_check_sync_time = time(NULL); last_check_sync_time = time(NULL);
os_thread_create(fts_optimize_thread, fts_optimize_wq, NULL); /* Add fts tables to fts slots which could be skipped
} during dict_load_table() because fts_optimize_thread
wasn't even started. */
mutex_enter(&dict_sys->mutex);
/**********************************************************************//** for (dict_table_t* table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
Check whether the work queue is initialized. table != NULL;
@return TRUE if optimze queue is initialized. */ table = UT_LIST_GET_NEXT(table_LRU, table)) {
UNIV_INTERN
ibool if (!table->fts || !dict_table_has_fts_index(table)) {
fts_optimize_is_init(void) continue;
/*======================*/ }
{
return(fts_optimize_wq != NULL); /* fts_optimize_thread is not started yet. So there is no
need to acqquire fts_optimize_wq->mutex for adding the fts
table to the fts slots. */
ut_ad(!table->can_be_evicted);
fts_optimize_new_table(table);
table->fts->in_queue = true;
}
mutex_exit(&dict_sys->mutex);
os_thread_create(fts_optimize_thread, fts_optimize_wq, NULL);
} }
/**********************************************************************//** /**********************************************************************//**
......
...@@ -285,9 +285,6 @@ struct fts_t { ...@@ -285,9 +285,6 @@ struct fts_t {
fts_add_wq. */ fts_add_wq. */
ib_mutex_t bg_threads_mutex; ib_mutex_t bg_threads_mutex;
/* 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 /* Whether the ADDED table record sync-ed afer
crash recovery; protected by bg_threads mutex */ crash recovery; protected by bg_threads mutex */
unsigned added_synced:1; unsigned added_synced:1;
...@@ -310,6 +307,11 @@ struct fts_t { ...@@ -310,6 +307,11 @@ struct fts_t {
ib_vector_t* indexes; /*!< Vector of FTS indexes, this is ib_vector_t* indexes; /*!< Vector of FTS indexes, this is
mainly for caching purposes. */ mainly for caching purposes. */
/* Whether the table was added to fts_optimize_wq();
protected by fts_optimize_wq mutex */
bool in_queue;
mem_heap_t* fts_heap; /*!< heap for fts_t allocation */ mem_heap_t* fts_heap; /*!< heap for fts_t allocation */
}; };
...@@ -631,14 +633,6 @@ void ...@@ -631,14 +633,6 @@ void
fts_optimize_init(void); fts_optimize_init(void);
/*====================*/ /*====================*/
/**********************************************************************//**
Check whether the work queue is initialized.
@return TRUE if optimze queue is initialized. */
UNIV_INTERN
ibool
fts_optimize_is_init(void);
/*======================*/
/****************************************************************//** /****************************************************************//**
Drops index ancillary tables for a FTS index Drops index ancillary tables for a FTS index
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
......
...@@ -25,6 +25,9 @@ Created 2011-02-15 Jimmy Yang ...@@ -25,6 +25,9 @@ Created 2011-02-15 Jimmy Yang
#ifndef INNODB_FTS0OPT_H #ifndef INNODB_FTS0OPT_H
#define INNODB_FTS0OPT_H #define INNODB_FTS0OPT_H
/** The FTS optimize thread's work queue. */
extern ib_wqueue_t* fts_optimize_wq;
/******************************************************************** /********************************************************************
Callback function to fetch the rows in an FTS INDEX record. */ Callback function to fetch the rows in an FTS INDEX record. */
UNIV_INTERN UNIV_INTERN
......
...@@ -56,16 +56,15 @@ ib_wqueue_free( ...@@ -56,16 +56,15 @@ ib_wqueue_free(
/*===========*/ /*===========*/
ib_wqueue_t* wq); /*!< in: work queue */ ib_wqueue_t* wq); /*!< in: work queue */
/****************************************************************//** /** Add a work item to the queue.
Add a work item to the queue. */ @param[in,out] wq work queue
@param[in] item work item
@param[in,out] heap memory heap to use for allocating list node
@param[in] wq_locked work queue mutex locked */
UNIV_INTERN UNIV_INTERN
void void
ib_wqueue_add( ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap,
/*==========*/ bool wq_locked = false);
ib_wqueue_t* wq, /*!< in: work queue */
void* item, /*!< in: work item */
mem_heap_t* heap); /*!< in: memory heap to use for allocating the
list node */
/******************************************************************** /********************************************************************
Check if queue is empty. */ Check if queue is empty. */
...@@ -104,7 +103,6 @@ ib_wqueue_nowait( ...@@ -104,7 +103,6 @@ ib_wqueue_nowait(
/*=============*/ /*=============*/
ib_wqueue_t* wq); /*<! in: work queue */ ib_wqueue_t* wq); /*<! in: work queue */
/******************************************************************** /********************************************************************
Get number of items on queue. Get number of items on queue.
@return number of items on queue */ @return number of items on queue */
...@@ -113,13 +111,16 @@ ib_wqueue_len( ...@@ -113,13 +111,16 @@ ib_wqueue_len(
/*==========*/ /*==========*/
ib_wqueue_t* wq); /*<! in: work queue */ ib_wqueue_t* wq); /*<! in: work queue */
/* Work queue. */ /** Work queue */
struct ib_wqueue_t { struct ib_wqueue_t
ib_mutex_t mutex; /*!< mutex protecting everything */ {
ib_list_t* items; /*!< work item list */ /** Mutex protecting everything */
os_event_t event; /*!< event we use to signal additions to list; ib_mutex_t mutex;
os_event_set() and os_event_reset() are /** Work item list */
protected by ib_wqueue_t::mutex */ ib_list_t* items;
/** event we use to signal additions to list;
os_event_set() and os_event_reset() are protected by the mutex */
os_event_t event;
}; };
#endif #endif
...@@ -60,23 +60,25 @@ ib_wqueue_free( ...@@ -60,23 +60,25 @@ ib_wqueue_free(
mem_free(wq); mem_free(wq);
} }
/****************************************************************//** /** Add a work item to the queue.
Add a work item to the queue. */ @param[in,out] wq work queue
@param[in] item work item
@param[in,out] heap memory heap to use for allocating list node
@param[in] wq_locked work queue mutex locked */
UNIV_INTERN UNIV_INTERN
void void
ib_wqueue_add( ib_wqueue_add(ib_wqueue_t* wq, void* item, mem_heap_t* heap, bool wq_locked)
/*==========*/
ib_wqueue_t* wq, /*!< in: work queue */
void* item, /*!< in: work item */
mem_heap_t* heap) /*!< in: memory heap to use for allocating the
list node */
{ {
mutex_enter(&wq->mutex); if (!wq_locked) {
mutex_enter(&wq->mutex);
}
ib_list_add_last(wq->items, item, heap); ib_list_add_last(wq->items, item, heap);
os_event_set(wq->event); os_event_set(wq->event);
mutex_exit(&wq->mutex); if (!wq_locked) {
mutex_exit(&wq->mutex);
}
} }
/****************************************************************//** /****************************************************************//**
......
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