diff options
author | Michael Widenius <monty@askmonty.org> | 2013-03-26 00:03:13 +0200 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2013-03-26 00:03:13 +0200 |
commit | 068c61978e3a81836d52b8caf11e044290159ad1 (patch) | |
tree | 2cbca861ab2cebe3bd99379ca9668bb483ca0d2a /storage/innobase/fts/fts0fts.cc | |
parent | 35bc8f9f4353b64da215e52ff6f1612a8ce66f43 (diff) | |
download | mariadb-git-068c61978e3a81836d52b8caf11e044290159ad1.tar.gz |
Temporary commit of 10.0-merge
Diffstat (limited to 'storage/innobase/fts/fts0fts.cc')
-rw-r--r-- | storage/innobase/fts/fts0fts.cc | 846 |
1 files changed, 485 insertions, 361 deletions
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index f716b980501..a81d3043e9c 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -36,12 +36,8 @@ Full Text Search interface #include "dict0priv.h" #include "dict0stats.h" #include "btr0pcur.h" -#include "row0row.h" -#include "ha_prototypes.h" -#ifdef UNIV_NONINL -#include "fts0priv.ic" -#endif +#include "ha_prototypes.h" #define FTS_MAX_ID_LEN 32 @@ -63,9 +59,6 @@ UNIV_INTERN ulong fts_min_token_size; ib_time_t elapsed_time = 0; ulint n_nodes = 0; -typedef struct fts_schema_struct fts_schema_t; -typedef struct fts_sys_table_struct fts_sys_table_t; - /** Error condition reported by fts_utf8_decode() */ const ulint UTF8_ERROR = 0xFFFFFFFF; @@ -142,7 +135,7 @@ const char *fts_default_stopword[] = }; /** For storing table info when checking for orphaned tables. */ -struct fts_sys_table_struct { +struct fts_aux_table_t { table_id_t id; /*!< Table id */ table_id_t parent_id; /*!< Parent table id */ table_id_t index_id; /*!< Table FT index id */ @@ -246,7 +239,7 @@ static const char* fts_config_table_insert_values_sql = FTS_OPTIMIZE_LIMIT_IN_SECS "', '180');\n" "" "INSERT INTO %s VALUES ('" - FTS_SYNCED_DOC_ID "', '1');\n" + FTS_SYNCED_DOC_ID "', '0');\n" "" "INSERT INTO %s VALUES ('" FTS_TOTAL_DELETED_COUNT "', '0');\n" @@ -257,12 +250,13 @@ static const char* fts_config_table_insert_values_sql = /****************************************************************//** Run SYNC on the table, i.e., write out data from the cache to the FTS auxiliary INDEX table and clear the cache at the end. -@return DB_SUCCESS if all OK */ +@return DB_SUCCESS if all OK */ static -ulint +dberr_t fts_sync( /*=====*/ - fts_sync_t* sync); /*!< in: sync state */ + fts_sync_t* sync) /*!< in: sync state */ + __attribute__((nonnull)); /****************************************************************//** Release all resources help by the words rb tree e.g., the node ilist. */ @@ -270,7 +264,8 @@ static void fts_words_free( /*===========*/ - ib_rbt_t* words); /*!< in: rb tree of words */ + ib_rbt_t* words) /*!< in: rb tree of words */ + __attribute__((nonnull)); #ifdef FTS_CACHE_SIZE_DEBUG /****************************************************************//** Read the max cache size parameter from the config table. */ @@ -294,19 +289,35 @@ fts_add_doc_by_id( doc_id_t doc_id, /*!< in: doc id */ ib_vector_t* fts_indexes __attribute__((unused))); /*!< in: affected fts indexes */ +#ifdef FTS_DOC_STATS_DEBUG /****************************************************************//** Check whether a particular word (term) exists in the FTS index. @return DB_SUCCESS if all went fine */ static -ulint +dberr_t fts_is_word_in_index( /*=================*/ trx_t* trx, /*!< in: FTS query state */ que_t** graph, /*!< out: Query graph */ fts_table_t* fts_table, /*!< in: table instance */ const fts_string_t* word, /*!< in: the word to check */ - ibool* found); /*!< out: TRUE if exists */ + ibool* found) /*!< out: TRUE if exists */ + __attribute__((nonnull, warn_unused_result)); +#endif /* FTS_DOC_STATS_DEBUG */ +/******************************************************************//** +Update the last document id. This function could create a new +transaction to update the last document id. +@return DB_SUCCESS if OK */ +static +dberr_t +fts_update_sync_doc_id( +/*===================*/ + const dict_table_t* table, /*!< in: table */ + const char* table_name, /*!< in: table name, or NULL */ + doc_id_t doc_id, /*!< in: last document id */ + trx_t* trx) /*!< in: update trx, or NULL */ + __attribute__((nonnull(1))); /******************************************************************** Check if we should stop. */ UNIV_INLINE @@ -443,7 +454,7 @@ fts_load_user_stopword( { pars_info_t* info; que_t* graph; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; ibool ret = TRUE; trx_t* trx; ibool has_lock = fts->fts_status & TABLE_DICT_LOCKED; @@ -507,9 +518,9 @@ fts_load_user_stopword( trx->error_state = DB_SUCCESS; } else { - fprintf(stderr, " InnoDB: Error: %lu " + fprintf(stderr, " InnoDB: Error '%s' " "while reading user stopword table.\n", - error); + ut_strerr(error)); ret = FALSE; break; } @@ -542,7 +553,7 @@ fts_index_cache_init( index_cache->words = rbt_create_arg_cmp( sizeof(fts_tokenizer_word_t), innobase_fts_text_cmp, - index_cache->charset); + (void*) index_cache->charset); ut_a(index_cache->doc_stats == NULL); @@ -670,7 +681,7 @@ fts_add_index( ib_vector_push(fts->indexes, &index); - index_cache = (fts_index_cache_t*) fts_find_index_cache(cache, index); + index_cache = fts_find_index_cache(cache, index); if (!index_cache) { /* Add new index cache structure */ @@ -805,7 +816,7 @@ fts_check_cached_index( Drop auxiliary tables related to an FTS index @return DB_SUCCESS or error number */ UNIV_INTERN -ulint +dberr_t fts_drop_index( /*===========*/ dict_table_t* table, /*!< in: Table where indexes are dropped */ @@ -813,7 +824,7 @@ fts_drop_index( trx_t* trx) /*!< in: Transaction for the drop */ { ib_vector_t* indexes = table->fts->indexes; - ulint err = DB_SUCCESS; + dberr_t err = DB_SUCCESS; ut_a(indexes); @@ -821,6 +832,8 @@ fts_drop_index( && (index == static_cast<dict_index_t*>( ib_vector_getp(table->fts->indexes, 0)))) || ib_vector_is_empty(indexes)) { + doc_id_t current_doc_id; + doc_id_t first_doc_id; /* If we are dropping the only FTS index of the table, remove it from optimize thread */ @@ -844,17 +857,20 @@ fts_drop_index( return(err); } + current_doc_id = table->fts->cache->next_doc_id; + first_doc_id = table->fts->cache->first_doc_id; fts_cache_clear(table->fts->cache, TRUE); fts_cache_destroy(table->fts->cache); table->fts->cache = fts_cache_create(table); + table->fts->cache->next_doc_id = current_doc_id; + table->fts->cache->first_doc_id = first_doc_id; } else { fts_cache_t* cache = table->fts->cache; fts_index_cache_t* index_cache; rw_lock_x_lock(&cache->init_lock); - index_cache = (fts_index_cache_t*) fts_find_index_cache( - cache, index); + index_cache = fts_find_index_cache(cache, index); if (index_cache->words) { fts_words_free(index_cache->words); @@ -1215,7 +1231,7 @@ fts_tokenizer_word_get( if (rbt_search(cache->stopword_info.cached_stopword, &parent, text) == 0) { - return NULL; + return(NULL); } /* Check if we found a match, if not then add word to tree. */ @@ -1445,38 +1461,40 @@ fts_cache_add_doc( /****************************************************************//** Drops a table. If the table can't be found we return a SUCCESS code. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_drop_table( /*===========*/ trx_t* trx, /*!< in: transaction */ const char* table_name) /*!< in: table to drop */ { - ulint error = DB_SUCCESS; + dict_table_t* table; + dberr_t error = DB_SUCCESS; - /* Check that the table exists in our data dictionary. */ - if (dict_table_get_low(table_name)) { + /* Check that the table exists in our data dictionary. + Similar to regular drop table case, we will open table with + DICT_ERR_IGNORE_INDEX_ROOT and DICT_ERR_IGNORE_CORRUPT option */ + table = dict_table_open_on_name( + table_name, TRUE, FALSE, + static_cast<dict_err_ignore_t>( + DICT_ERR_IGNORE_INDEX_ROOT | DICT_ERR_IGNORE_CORRUPT)); -#ifdef FTS_INTERNAL_DIAG_PRINT - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Dropping %s\n", table_name); -#endif + if (table != 0) { - error = row_drop_table_for_mysql(table_name, trx, TRUE); + dict_table_close(table, TRUE, FALSE); + + /* Pass nonatomic=false (dont allow data dict unlock), + because the transaction may hold locks on SYS_* tables from + previous calls to fts_drop_table(). */ + error = row_drop_table_for_mysql(table_name, trx, true, false); - /* We only return the status of the last error. */ if (error != DB_SUCCESS) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: (%lu) dropping " - "FTS index table %s\n", error, table_name); + ib_logf(IB_LOG_LEVEL_ERROR, + "Unable to drop FTS index aux table %s: %s", + table_name, ut_strerr(error)); } } else { - ut_print_timestamp(stderr); - - /* FIXME: Should provide appropriate error return code - rather than printing message indiscriminately. */ - fprintf(stderr, " InnoDB: %s not found.\n", - table_name); + error = DB_FAIL; } return(error); @@ -1487,8 +1505,8 @@ Drops the common ancillary tables needed for supporting an FTS index on the given table. row_mysql_lock_data_dictionary must have been called before this. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_drop_common_tables( /*===================*/ trx_t* trx, /*!< in: transaction */ @@ -1496,10 +1514,10 @@ fts_drop_common_tables( index */ { ulint i; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; for (i = 0; fts_common_tables[i] != NULL; ++i) { - ulint err; + dberr_t err; char* table_name; fts_table->suffix = fts_common_tables[i]; @@ -1509,7 +1527,7 @@ fts_drop_common_tables( err = fts_drop_table(trx, table_name); /* We only return the status of the last error. */ - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS && err != DB_FAIL) { error = err; } @@ -1520,11 +1538,11 @@ fts_drop_common_tables( } /****************************************************************//** -Since we do a horizontal split on the index table, we need to drop the +Since we do a horizontal split on the index table, we need to drop all the split tables. @return DB_SUCCESS or error code */ UNIV_INTERN -ulint +dberr_t fts_drop_index_split_tables( /*========================*/ trx_t* trx, /*!< in: transaction */ @@ -1533,12 +1551,12 @@ fts_drop_index_split_tables( { ulint i; fts_table_t fts_table; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; FTS_INIT_INDEX_TABLE(&fts_table, NULL, FTS_INDEX_TABLE, index); for (i = 0; fts_index_selector[i].value; ++i) { - ulint err; + dberr_t err; char* table_name; fts_table.suffix = fts_get_suffix(i); @@ -1548,7 +1566,7 @@ fts_drop_index_split_tables( err = fts_drop_table(trx, table_name); /* We only return the status of the last error. */ - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS && err != DB_FAIL) { error = err; } @@ -1562,23 +1580,21 @@ fts_drop_index_split_tables( Drops FTS auxiliary tables for an FTS index @return DB_SUCCESS or error code */ UNIV_INTERN -ulint +dberr_t fts_drop_index_tables( /*==================*/ trx_t* trx, /*!< in: transaction */ dict_index_t* index) /*!< in: Index to drop */ { - ulint err; - ulint error = DB_SUCCESS; fts_table_t fts_table; - ulint j; + dberr_t error = DB_SUCCESS; static const char* index_tables[] = { "DOC_ID", NULL }; - err = fts_drop_index_split_tables(trx, index); + dberr_t err = fts_drop_index_split_tables(trx, index); /* We only return the status of the last error. */ if (err != DB_SUCCESS) { @@ -1587,18 +1603,17 @@ fts_drop_index_tables( FTS_INIT_INDEX_TABLE(&fts_table, NULL, FTS_INDEX_TABLE, index); - for (j = 0; index_tables[j] != NULL; ++j) { - ulint err; + for (ulint i = 0; index_tables[i] != NULL; ++i) { char* table_name; - fts_table.suffix = index_tables[j]; + fts_table.suffix = index_tables[i]; table_name = fts_get_table_name(&fts_table); err = fts_drop_table(trx, table_name); /* We only return the status of the last error. */ - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS && err != DB_FAIL) { error = err; } @@ -1613,18 +1628,20 @@ Drops FTS ancillary tables needed for supporting an FTS index on the given table. row_mysql_lock_data_dictionary must have been called before this. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_drop_all_index_tables( /*======================*/ trx_t* trx, /*!< in: transaction */ fts_t* fts) /*!< in: fts instance */ { - ulint i; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; - for (i = 0; i < ib_vector_size(fts->indexes); ++i) { - ulint err; + for (ulint i = 0; + fts->indexes != 0 && i < ib_vector_size(fts->indexes); + ++i) { + + dberr_t err; dict_index_t* index; index = static_cast<dict_index_t*>( @@ -1646,17 +1663,19 @@ given table. row_mysql_lock_data_dictionary must have been called before this. @return DB_SUCCESS or error code */ UNIV_INTERN -ulint +dberr_t fts_drop_tables( /*============*/ trx_t* trx, /*!< in: transaction */ dict_table_t* table) /*!< in: table has the FTS index */ { - ulint error; + dberr_t error; fts_table_t fts_table; FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table); + /* TODO: This is not atomic and can cause problems during recovery. */ + error = fts_drop_common_tables(trx, &fts_table); if (error == DB_SUCCESS) { @@ -1692,20 +1711,20 @@ on the given table. row_mysql_lock_data_dictionary must have been called before this. @return DB_SUCCESS if succeed */ UNIV_INTERN -ulint +dberr_t fts_create_common_tables( /*=====================*/ - trx_t* trx, /*!< in: transaction */ - const dict_table_t* table, /*!< in: table with FTS index */ - const char* name, /*!< in: table name normalized.*/ - ibool skip_doc_id_index) /*!< in: Skip index on doc id */ - + trx_t* trx, /*!< in: transaction */ + const dict_table_t* table, /*!< in: table with FTS index */ + const char* name, /*!< in: table name normalized.*/ + bool skip_doc_id_index)/*!< in: Skip index on doc id */ { char* sql; - ulint error; + dberr_t error; que_t* graph; fts_table_t fts_table; mem_heap_t* heap = mem_heap_create(1024); + pars_info_t* info; FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table); @@ -1744,17 +1763,23 @@ fts_create_common_tables( goto func_exit; } + info = pars_info_create(); + + pars_info_bind_id(info, TRUE, "table_name", name); + pars_info_bind_id(info, TRUE, "index_name", FTS_DOC_ID_INDEX_NAME); + pars_info_bind_id(info, TRUE, "doc_id_col_name", FTS_DOC_ID_COL_NAME); + /* Create the FTS DOC_ID index on the hidden column. Currently this is common for any FT index created on the table. */ graph = fts_parse_sql_no_dict_lock( NULL, - NULL, + info, mem_heap_printf( heap, "BEGIN\n" "" - "CREATE UNIQUE INDEX %s ON %s(%s);\n", - FTS_DOC_ID_INDEX_NAME, name, FTS_DOC_ID_COL_NAME)); + "CREATE UNIQUE INDEX $index_name ON $table_name(" + "$doc_id_col_name);\n")); error = fts_eval_sql(trx, graph); que_graph_free(graph); @@ -1794,7 +1819,7 @@ fts_create_one_index_table( dict_field_t* field; dict_table_t* new_table = NULL; char* table_name = fts_get_table_name(fts_table); - ulint error; + dberr_t error; CHARSET_INFO* charset; ut_ad(index->type & DICT_FTS); @@ -1828,14 +1853,14 @@ fts_create_one_index_table( dict_mem_table_add_col(new_table, heap, "ilist", DATA_BLOB, 4130048, 0); - error = row_create_table_for_mysql(new_table, trx); + error = row_create_table_for_mysql(new_table, trx, true); if (error != DB_SUCCESS) { - trx->error_state = static_cast<db_err>(error); + trx->error_state = error; dict_mem_table_free(new_table); new_table = NULL; - fprintf(stderr, " InnoDB: Warning: Fail to create FTS " - " index table %s \n", table_name); + ib_logf(IB_LOG_LEVEL_WARN, + "Fail to create FTS index table %s", table_name); } mem_free(table_name); @@ -1848,7 +1873,7 @@ Wrapper function of fts_create_index_tables_low(), create auxiliary tables for an FTS index @return: DB_SUCCESS or error code */ UNIV_INTERN -ulint +dberr_t fts_create_index_tables_low( /*========================*/ trx_t* trx, /*!< in: transaction */ @@ -1862,7 +1887,7 @@ fts_create_index_tables_low( char* sql; que_t* graph; fts_table_t fts_table; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; mem_heap_t* heap = mem_heap_create(1024); fts_table.type = FTS_INDEX_TABLE; @@ -1874,6 +1899,7 @@ fts_create_index_tables_low( /* Create the FTS auxiliary tables that are specific to an FTS index. */ sql = fts_prepare_sql(&fts_table, fts_create_index_tables_sql); + graph = fts_parse_sql_no_dict_lock(NULL, NULL, sql); mem_free(sql); @@ -1903,9 +1929,7 @@ fts_create_index_tables_low( que_graph_free(graph); } - if (error == DB_SUCCESS) { - error = fts_sql_commit(trx); - } else { + if (error != DB_SUCCESS) { /* We have special error handling here */ trx->error_state = DB_SUCCESS; @@ -1928,18 +1952,25 @@ FTS index on the given table. row_mysql_lock_data_dictionary must have been called before this. @return DB_SUCCESS or error code */ UNIV_INTERN -ulint +dberr_t fts_create_index_tables( /*====================*/ trx_t* trx, /*!< in: transaction */ const dict_index_t* index) /*!< in: the index instance */ { + dberr_t err; dict_table_t* table; table = dict_table_get_low(index->table_name); ut_a(table != NULL); - return(fts_create_index_tables_low(trx, index, table->name, table->id)); + err = fts_create_index_tables_low(trx, index, table->name, table->id); + + if (err == DB_SUCCESS) { + trx_commit(trx); + } + + return(err); } #if 0 /******************************************************************//** @@ -1953,22 +1984,22 @@ fts_get_state_str( { switch (state) { case FTS_INSERT: - return "INSERT"; + return("INSERT"); case FTS_MODIFY: - return "MODIFY"; + return("MODIFY"); case FTS_DELETE: - return "DELETE"; + return("DELETE"); case FTS_NOTHING: - return "NOTHING"; + return("NOTHING"); case FTS_INVALID: - return "INVALID"; + return("INVALID"); default: - return "UNKNOWN"; + return("UNKNOWN"); } } #endif @@ -2321,7 +2352,7 @@ fts_get_max_cache_size( trx_t* trx, /*!< in: transaction */ fts_table_t* fts_table) /*!< in: table instance */ { - ulint error; + dberr_t error; fts_string_t value; ulint cache_size_in_mb; @@ -2381,32 +2412,19 @@ fts_get_max_cache_size( } #endif -/*********************************************************************//** -Get the total number of documents in the FTS. -@return estimated number of rows in the table */ -UNIV_INTERN -ulint -fts_get_total_document_count( -/*=========================*/ - dict_table_t* table) /*!< in: table instance */ -{ - ut_ad(table->stat_initialized); - - return((ulint) table->stat_n_rows); -} - +#ifdef FTS_DOC_STATS_DEBUG /*********************************************************************//** Get the total number of words in the FTS for a particular FTS index. @return DB_SUCCESS if all OK else error code */ UNIV_INTERN -ulint +dberr_t fts_get_total_word_count( /*=====================*/ trx_t* trx, /*!< in: transaction */ dict_index_t* index, /*!< in: for this index */ ulint* total) /* out: total words */ { - ulint error; + dberr_t error; fts_string_t value; *total = 0; @@ -2426,14 +2444,15 @@ fts_get_total_word_count( *total = strtoul((char*) value.f_str, NULL, 10); } else { ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: (%lu) reading total words " - "value from config table\n", error); + fprintf(stderr, " InnoDB: Error: (%s) reading total words " + "value from config table\n", ut_strerr(error)); } ut_free(value.f_str); return(error); } +#endif /* FTS_DOC_STATS_DEBUG */ /*********************************************************************//** Update the next and last Doc ID in the CONFIG table to be the input @@ -2443,8 +2462,9 @@ UNIV_INTERN void fts_update_next_doc_id( /*===================*/ + trx_t* trx, /*!< in/out: transaction */ const dict_table_t* table, /*!< in: table */ - const char* table_name, /*!< in: table name */ + const char* table_name, /*!< in: table name, or NULL */ doc_id_t doc_id) /*!< in: DOC ID to set */ { table->fts->cache->synced_doc_id = doc_id; @@ -2453,7 +2473,7 @@ fts_update_next_doc_id( table->fts->cache->first_doc_id = table->fts->cache->next_doc_id; fts_update_sync_doc_id( - table, table_name, table->fts->cache->synced_doc_id, NULL); + table, table_name, table->fts->cache->synced_doc_id, trx); } @@ -2461,7 +2481,7 @@ fts_update_next_doc_id( Get the next available document id. @return DB_SUCCESS if OK */ UNIV_INTERN -ulint +dberr_t fts_get_next_doc_id( /*================*/ const dict_table_t* table, /*!< in: table */ @@ -2494,8 +2514,8 @@ fts_get_next_doc_id( This function fetch the Doc ID from CONFIG table, and compare with the Doc ID supplied. And store the larger one to the CONFIG table. @return DB_SUCCESS if OK */ -UNIV_INTERN -ulint +static __attribute__((nonnull)) +dberr_t fts_cmp_set_sync_doc_id( /*====================*/ const dict_table_t* table, /*!< in: table */ @@ -2509,7 +2529,7 @@ fts_cmp_set_sync_doc_id( { trx_t* trx; pars_info_t* info; - ulint error; + dberr_t error; fts_table_t fts_table; que_t* graph = NULL; fts_cache_t* cache = table->fts->cache; @@ -2559,8 +2579,6 @@ retry: goto func_exit; } - ut_a(*doc_id > 0); - if (read_only) { goto func_exit; } @@ -2594,8 +2612,8 @@ func_exit: *doc_id = 0; ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: (%lu) " - "while getting next doc id.\n", error); + fprintf(stderr, " InnoDB: Error: (%s) " + "while getting next doc id.\n", ut_strerr(error)); fts_sql_rollback(trx); @@ -2614,23 +2632,23 @@ func_exit: Update the last document id. This function could create a new transaction to update the last document id. @return DB_SUCCESS if OK */ -UNIV_INTERN -ulint +static +dberr_t fts_update_sync_doc_id( /*===================*/ const dict_table_t* table, /*!< in: table */ - const char* table_name, /*!< in: table name */ + const char* table_name, /*!< in: table name, or NULL */ doc_id_t doc_id, /*!< in: last document id */ - trx_t* trx) /*!< in: update trx */ + trx_t* trx) /*!< in: update trx, or NULL */ { byte id[FTS_MAX_ID_LEN]; pars_info_t* info; fts_table_t fts_table; ulint id_len; que_t* graph = NULL; - ulint error; + dberr_t error; ibool local_trx = FALSE; - fts_cache_t* cache = table->fts->cache;; + fts_cache_t* cache = table->fts->cache; fts_table.suffix = "CONFIG"; fts_table.table_id = table->id; @@ -2651,8 +2669,7 @@ fts_update_sync_doc_id( info = pars_info_create(); - // FIXME: Get rid of snprintf - id_len = snprintf( + id_len = ut_snprintf( (char*) id, sizeof(id), FTS_DOC_ID_FORMAT, doc_id + 1); pars_info_bind_varchar_literal(info, "doc_id", id, id_len); @@ -2672,9 +2689,10 @@ fts_update_sync_doc_id( fts_sql_commit(trx); cache->synced_doc_id = doc_id; } else { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: (%lu) " - "while updating last doc id.\n", error); + + ib_logf(IB_LOG_LEVEL_ERROR, + "(%s) while updating last doc id.", + ut_strerr(error)); fts_sql_rollback(trx); } @@ -2725,15 +2743,15 @@ fts_doc_ids_free( /*********************************************************************//** Do commit-phase steps necessary for the insertion of a new row. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_add( /*====*/ fts_trx_table_t*ftt, /*!< in: FTS trx table */ fts_trx_row_t* row) /*!< in: row */ { dict_table_t* table = ftt->table; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; doc_id_t doc_id = row->doc_id; ut_a(row->state == FTS_INSERT || row->state == FTS_MODIFY); @@ -2757,8 +2775,8 @@ fts_add( /*********************************************************************//** Do commit-phase steps necessary for the deletion of a row. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_delete( /*=======*/ fts_trx_table_t*ftt, /*!< in: FTS trx table */ @@ -2766,7 +2784,7 @@ fts_delete( { que_t* graph; fts_table_t fts_table; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; doc_id_t write_doc_id; dict_table_t* table = ftt->table; doc_id_t doc_id = row->doc_id; @@ -2848,14 +2866,14 @@ fts_delete( /*********************************************************************//** Do commit-phase steps necessary for the modification of a row. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_modify( /*=======*/ fts_trx_table_t* ftt, /*!< in: FTS trx table */ fts_trx_row_t* row) /*!< in: row */ { - ulint error; + dberr_t error; ut_a(row->state == FTS_MODIFY); @@ -2872,7 +2890,7 @@ fts_modify( Create a new document id. @return DB_SUCCESS if all went well else error */ UNIV_INTERN -ulint +dberr_t fts_create_doc_id( /*==============*/ dict_table_t* table, /*!< in: row is of this table. */ @@ -2882,7 +2900,7 @@ fts_create_doc_id( mem_heap_t* heap) /*!< in: heap */ { doc_id_t doc_id; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; ut_a(table->fts->doc_col != ULINT_UNDEFINED); @@ -2919,15 +2937,15 @@ fts_create_doc_id( The given transaction is about to be committed; do whatever is necessary from the FTS system's POV. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_commit_table( /*=============*/ fts_trx_table_t* ftt) /*!< in: FTS table to commit*/ { const ib_rbt_node_t* node; ib_rbt_t* rows; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; fts_cache_t* cache = ftt->table->fts->cache; trx_t* trx = trx_allocate_for_background(); @@ -2979,13 +2997,13 @@ The given transaction is about to be committed; do whatever is necessary from the FTS system's POV. @return DB_SUCCESS or error code */ UNIV_INTERN -ulint +dberr_t fts_commit( /*=======*/ trx_t* trx) /*!< in: transaction */ { const ib_rbt_node_t* node; - ulint error; + dberr_t error; ib_rbt_t* tables; fts_savepoint_t* savepoint; @@ -3008,10 +3026,9 @@ fts_commit( } /*********************************************************************//** -Create a new empty document. -@return new document */ +Initialize a document. */ UNIV_INTERN -fts_doc_t* +void fts_doc_init( /*=========*/ fts_doc_t* doc) /*!< in: doc to initialize */ @@ -3021,8 +3038,6 @@ fts_doc_init( memset(doc, 0, sizeof(*doc)); doc->self_heap = ib_heap_allocator_create(heap); - - return(doc); } /*********************************************************************//** @@ -3075,7 +3090,7 @@ fts_fetch_row_id( /*********************************************************************//** Callback function for fetch that stores the text of an FTS document, converting each column to UTF-16. -@return: always returns FALSE */ +@return always FALSE */ UNIV_INTERN ibool fts_query_expansion_fetch_doc( @@ -3467,13 +3482,15 @@ fts_get_max_doc_id( dfield = dict_index_get_nth_field(index, 0); +#if 0 /* This can fail when renaming a column to FTS_DOC_ID_COL_NAME. */ ut_ad(innobase_strcasecmp(FTS_DOC_ID_COL_NAME, dfield->name) == 0); +#endif mtr_start(&mtr); /* fetch the largest indexes value */ btr_pcur_open_at_index_side( - FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); + false, index, BTR_SEARCH_LEAF, &pcur, true, 0, &mtr); if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) { const rec_t* rec = NULL; @@ -3516,13 +3533,14 @@ func_exit: Fetch document with the given document id. @return DB_SUCCESS if OK else error */ UNIV_INTERN -ulint +dberr_t fts_doc_fetch_by_doc_id( /*====================*/ fts_get_doc_t* get_doc, /*!< in: state */ doc_id_t doc_id, /*!< in: id of document to fetch */ - dict_index_t* index_to_use, /*!< in: caller supplied FTS index */ + dict_index_t* index_to_use, /*!< in: caller supplied FTS index, + or NULL */ ulint option, /*!< in: search option, if it is greater than doc_id or equal */ fts_sql_callback @@ -3530,7 +3548,7 @@ fts_doc_fetch_by_doc_id( void* arg) /*!< in: callback arg */ { pars_info_t* info; - ulint error; + dberr_t error; const char* select_str; doc_id_t write_doc_id; dict_index_t* index; @@ -3555,6 +3573,7 @@ fts_doc_fetch_by_doc_id( pars_info_bind_function(info, "my_func", callback, arg); select_str = fts_get_select_columns_str(index, info, info->heap); + pars_info_bind_id(info, TRUE, "table_name", index->table_name); if (!get_doc || !get_doc->get_document_graph) { if (option == FTS_FETCH_DOC_BY_ID_EQUAL) { @@ -3564,7 +3583,7 @@ fts_doc_fetch_by_doc_id( mem_heap_printf(info->heap, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" - " SELECT %s FROM %s" + " SELECT %s FROM $table_name" " WHERE %s = :doc_id;\n" "BEGIN\n" "" @@ -3576,20 +3595,32 @@ fts_doc_fetch_by_doc_id( " END IF;\n" "END LOOP;\n" "CLOSE c;", - select_str, index->table_name, - FTS_DOC_ID_COL_NAME)); + select_str, FTS_DOC_ID_COL_NAME)); } else { ut_ad(option == FTS_FETCH_DOC_BY_ID_LARGE); + /* This is used for crash recovery of table with + hidden DOC ID or FTS indexes. We will scan the table + to re-processing user table rows whose DOC ID or + FTS indexed documents have not been sync-ed to disc + during recent crash. + In the case that all fulltext indexes are dropped + for a table, we will keep the "hidden" FTS_DOC_ID + column, and this scan is to retreive the largest + DOC ID being used in the table to determine the + appropriate next DOC ID. + In the case of there exists fulltext index(es), this + operation will re-tokenize any docs that have not + been sync-ed to the disk, and re-prime the FTS + cached */ graph = fts_parse_sql( NULL, info, mem_heap_printf(info->heap, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" - " SELECT %s, %s FROM %s" - " WHERE %s > :doc_id" - " ORDER BY %s;\n" + " SELECT %s, %s FROM $table_name" + " WHERE %s > :doc_id;\n" "BEGIN\n" "" "OPEN c;\n" @@ -3601,9 +3632,7 @@ fts_doc_fetch_by_doc_id( "END LOOP;\n" "CLOSE c;", FTS_DOC_ID_COL_NAME, - select_str, index->table_name, - FTS_DOC_ID_COL_NAME, - FTS_DOC_ID_COL_NAME)); + select_str, FTS_DOC_ID_COL_NAME)); } if (get_doc) { get_doc->get_document_graph = graph; @@ -3633,7 +3662,7 @@ fts_doc_fetch_by_doc_id( Write out a single word's data as new entry/entries in the INDEX table. @return DB_SUCCESS if all OK. */ UNIV_INTERN -ulint +dberr_t fts_write_node( /*===========*/ trx_t* trx, /*!< in: transaction */ @@ -3643,7 +3672,7 @@ fts_write_node( fts_node_t* node) /*!< in: node columns */ { pars_info_t* info; - ulint error; + dberr_t error; ib_uint32_t doc_count; ib_time_t start_time; doc_id_t last_doc_id; @@ -3698,8 +3727,8 @@ fts_write_node( /*********************************************************************//** Add rows to the DELETED_CACHE table. @return DB_SUCCESS if all went well else error code*/ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_sync_add_deleted_cache( /*=======================*/ fts_sync_t* sync, /*!< in: sync state */ @@ -3710,7 +3739,7 @@ fts_sync_add_deleted_cache( que_t* graph; fts_table_t fts_table; doc_id_t dummy = 0; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; ulint n_elems = ib_vector_size(doc_ids); ut_a(ib_vector_size(doc_ids) > 0); @@ -3748,9 +3777,10 @@ fts_sync_add_deleted_cache( } /*********************************************************************//** -Write the words and ilist to disk.*/ -static -ulint +Write the words and ilist to disk. +@return DB_SUCCESS if all went well else error code */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_sync_write_words( /*=================*/ trx_t* trx, /*!< in: transaction */ @@ -3761,10 +3791,12 @@ fts_sync_write_words( ulint n_nodes = 0; ulint n_words = 0; const ib_rbt_node_t* rbt_node; - ulint n_new_words = 0; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; ibool print_error = FALSE; +#ifdef FTS_DOC_STATS_DEBUG dict_table_t* table = index_cache->index->table; + ulint n_new_words = 0; +#endif /* FTS_DOC_STATS_DEBUG */ FTS_INIT_INDEX_TABLE( &fts_table, NULL, FTS_INDEX_TABLE, index_cache->index); @@ -3789,9 +3821,10 @@ fts_sync_write_words( fts_table.suffix = fts_get_suffix(selected); +#ifdef FTS_DOC_STATS_DEBUG /* Check if the word exists in the FTS index and if not then we need to increment the total word count stats. */ - if (error == DB_SUCCESS) { + if (error == DB_SUCCESS && fts_enable_diag_print) { ibool found = FALSE; error = fts_is_word_in_index( @@ -3805,6 +3838,7 @@ fts_sync_write_words( ++n_new_words; } } +#endif /* FTS_DOC_STATS_DEBUG */ n_nodes += ib_vector_size(word->nodes); @@ -3829,9 +3863,9 @@ fts_sync_write_words( if (error != DB_SUCCESS && !print_error) { ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error (%lu) writing " + fprintf(stderr, " InnoDB: Error (%s) writing " "word node to FTS auxiliary index " - "table.\n", error); + "table.\n", ut_strerr(error)); print_error = TRUE; } @@ -3840,19 +3874,23 @@ fts_sync_write_words( ut_free(rbt_remove_node(index_cache->words, rbt_node)); } - if (error == DB_SUCCESS && n_new_words > 0) { +#ifdef FTS_DOC_STATS_DEBUG + if (error == DB_SUCCESS && n_new_words > 0 && fts_enable_diag_print) { fts_table_t fts_table; FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table); /* Increment the total number of words in the FTS index */ - fts_config_increment_index_value( + error = fts_config_increment_index_value( trx, index_cache->index, FTS_TOTAL_WORD_COUNT, n_new_words); } +#endif /* FTS_DOC_STATS_DEBUG */ - printf("Avg number of nodes: %lf\n", - (double) n_nodes / (double) (n_words > 1 ? n_words : 1)); + if (fts_enable_diag_print) { + printf("Avg number of nodes: %lf\n", + (double) n_nodes / (double) (n_words > 1 ? n_words : 1)); + } return(error); } @@ -3861,8 +3899,8 @@ fts_sync_write_words( /*********************************************************************//** Write a single documents statistics to disk. @return DB_SUCCESS if all went well else error code */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_sync_write_doc_stat( /*====================*/ trx_t* trx, /*!< in: transaction */ @@ -3872,7 +3910,7 @@ fts_sync_write_doc_stat( { pars_info_t* info; doc_id_t doc_id; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; ib_uint32_t word_count; if (*graph) { @@ -3918,9 +3956,9 @@ fts_sync_write_doc_stat( trx->error_state = DB_SUCCESS; } else { - fprintf(stderr, " InnoDB: Error: %lu " + fprintf(stderr, " InnoDB: Error: (%s) " "while writing to FTS doc_id.\n", - error); + ut_strerr(error)); break; /* Exit the loop. */ } @@ -3940,7 +3978,7 @@ fts_sync_write_doc_stats( trx_t* trx, /*!< in: transaction */ const fts_index_cache_t*index_cache) /*!< in: index cache */ { - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; que_t* graph = NULL; fts_doc_stats_t* doc_stat; @@ -3973,7 +4011,6 @@ fts_sync_write_doc_stats( return(error); } -#endif /* FTS_DOC_STATS_DEBUG */ /*********************************************************************//** Callback to check the existince of a word. @@ -4007,13 +4044,12 @@ fts_lookup_word( } /*********************************************************************//** -Check whether a particular word (term) exists in the FTS index. */ +Check whether a particular word (term) exists in the FTS index. +@return DB_SUCCESS if all went well else error code */ static -ulint +dberr_t fts_is_word_in_index( /*=================*/ - /* out: DB_SUCCESS if all went - well else error code */ trx_t* trx, /*!< in: FTS query state */ que_t** graph, /* out: Query graph */ fts_table_t* fts_table, /*!< in: table instance */ @@ -4022,7 +4058,7 @@ fts_is_word_in_index( ibool* found) /* out: TRUE if exists */ { pars_info_t* info; - ulint error; + dberr_t error; trx->op_info = "looking up word in FTS index"; @@ -4073,8 +4109,9 @@ fts_is_word_in_index( trx->error_state = DB_SUCCESS; } else { - fprintf(stderr, " InnoDB: Error: %lu " - "while reading FTS index.\n", error); + fprintf(stderr, " InnoDB: Error: (%s) " + "while reading FTS index.\n", + ut_strerr(error)); break; /* Exit the loop. */ } @@ -4083,6 +4120,7 @@ fts_is_word_in_index( return(error); } +#endif /* FTS_DOC_STATS_DEBUG */ /*********************************************************************//** Begin Sync, create transaction, acquire locks, etc. */ @@ -4101,29 +4139,36 @@ fts_sync_begin( sync->trx = trx_allocate_for_background(); - ut_print_timestamp(stderr); - fprintf(stderr, " SYNC deleted count: %ld size: %lu bytes\n", - ib_vector_size(cache->deleted_doc_ids), cache->total_size); + if (fts_enable_diag_print) { + ib_logf(IB_LOG_LEVEL_INFO, + "FTS SYNC for table %s, deleted count: %ld size: " + "%lu bytes", + sync->table->name, + ib_vector_size(cache->deleted_doc_ids), + cache->total_size); + } } /*********************************************************************//** Run SYNC on the table, i.e., write out data from the index specific -cache to the FTS aux INDEX table and FTS aux doc id stats table. */ -static -ulint +cache to the FTS aux INDEX table and FTS aux doc id stats table. +@return DB_SUCCESS if all OK */ +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_sync_index( /*===========*/ - /* out: DB_SUCCESS if all OK */ fts_sync_t* sync, /*!< in: sync state */ fts_index_cache_t* index_cache) /*!< in: index cache */ { trx_t* trx = sync->trx; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; trx->op_info = "doing SYNC index"; - ut_print_timestamp(stderr); - fprintf(stderr, " SYNC words: %ld\n", rbt_size(index_cache->words)); + if (fts_enable_diag_print) { + ib_logf(IB_LOG_LEVEL_INFO, + "SYNC words: %ld", rbt_size(index_cache->words)); + } ut_ad(rbt_validate(index_cache->words)); @@ -4146,13 +4191,13 @@ fts_sync_index( /*********************************************************************//** Commit the SYNC, change state of processed doc ids etc. @return DB_SUCCESS if all OK */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t fts_sync_commit( /*============*/ fts_sync_t* sync) /*!< in: sync state */ { - ulint error; + dberr_t error; trx_t* trx = sync->trx; fts_cache_t* cache = sync->table->fts->cache; doc_id_t last_doc_id; @@ -4191,13 +4236,18 @@ fts_sync_commit( fts_sql_rollback(trx); ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: (%lu) during SYNC.\n", error); + fprintf(stderr, " InnoDB: Error: (%s) during SYNC.\n", + ut_strerr(error)); } - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: SYNC time : %lusecs: elapsed %lf ins/sec\n", - (ulong) (ut_time() - sync->start_time), - (double) n_nodes/ (double) elapsed_time); + if (fts_enable_diag_print && elapsed_time) { + ib_logf(IB_LOG_LEVEL_INFO, + "SYNC for table %s: SYNC time : %lu secs: " + "elapsed %lf ins/sec", + sync->table->name, + (ulong) (ut_time() - sync->start_time), + (double) n_nodes/ (double) elapsed_time); + } trx_free_for_background(trx); @@ -4226,13 +4276,13 @@ Run SYNC on the table, i.e., write out data from the cache to the FTS auxiliary INDEX table and clear the cache at the end. @return DB_SUCCESS if all OK */ static -ulint +dberr_t fts_sync( /*=====*/ fts_sync_t* sync) /*!< in: sync state */ { ulint i; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; fts_cache_t* cache = sync->table->fts->cache; rw_lock_x_lock(&cache->lock); @@ -4275,34 +4325,28 @@ fts_sync( /****************************************************************//** Run SYNC on the table, i.e., write out data from the cache to the -FTS auxiliary INDEX table and clear the cache at the end. -@return DB_SUCCESS if all OK */ +FTS auxiliary INDEX table and clear the cache at the end. */ UNIV_INTERN -ulint +void fts_sync_table( /*===========*/ dict_table_t* table) /*!< in: table */ { - ulint error = DB_SUCCESS; - ut_ad(table->fts); if (table->fts->cache) { fts_sync(table->fts->cache->sync); } - - return(error); } /******************************************************************** Process next token from document starting at the given position, i.e., add -the token's start position to the token's list of positions. */ +the token's start position to the token's list of positions. +@return number of characters handled in this call */ static ulint fts_process_token( /*==============*/ - /* out: number of characters - handled in this call */ fts_doc_t* doc, /* in/out: document to tokenize */ fts_doc_t* result, /* out: if provided, save @@ -4406,7 +4450,7 @@ fts_tokenize_document( ut_a(doc->charset); doc->tokens = rbt_create_arg_cmp( - sizeof(fts_token_t), innobase_fts_text_cmp, doc->charset); + sizeof(fts_token_t), innobase_fts_text_cmp, (void*) doc->charset); for (ulint i = 0; i < doc->text.f_len; i += inc) { inc = fts_process_token(doc, result, i, 0); @@ -4473,6 +4517,7 @@ fts_get_docs_create( memset(get_doc, 0x0, sizeof(*get_doc)); get_doc->index_cache = fts_get_index_cache(cache, *index); + get_doc->cache = cache; /* Must find the index cache. */ ut_a(get_doc->index_cache != NULL); @@ -4520,11 +4565,14 @@ fts_init_doc_id( rw_lock_x_lock(&table->fts->cache->lock); + /* Return if the table is already initialized for DOC ID */ if (table->fts->cache->first_doc_id != FTS_NULL_DOC_ID) { rw_lock_x_unlock(&table->fts->cache->lock); return(0); } + DEBUG_SYNC_C("fts_initialize_doc_id"); + /* Then compare this value with the ID value stored in the CONFIG table. The larger one will be our new initial Doc ID */ fts_cmp_set_sync_doc_id(table, 0, FALSE, &max_doc_id); @@ -4591,7 +4639,7 @@ fts_get_rows_count( trx_t* trx; pars_info_t* info; que_t* graph; - ulint error; + dberr_t error; ulint count = 0; trx = trx_allocate_for_background(); @@ -4639,9 +4687,9 @@ fts_get_rows_count( trx->error_state = DB_SUCCESS; } else { - fprintf(stderr, " InnoDB: Error: %lu " + fprintf(stderr, " InnoDB: Error: (%s) " "while reading FTS table.\n", - error); + ut_strerr(error)); break; /* Exit the loop. */ } @@ -4678,7 +4726,7 @@ fts_update_max_cache_size( trx_free_for_background(trx); } -#endif +#endif /* FTS_CACHE_SIZE_DEBUG */ /*********************************************************************//** Free the modified rows of a table. */ @@ -4861,13 +4909,13 @@ fts_get_doc_id_from_rec( col_no = dict_col_get_clust_pos( &table->cols[table->fts->doc_col], clust_index); + ut_ad(col_no != ULINT_UNDEFINED); - /* We have no choice but to cast rec here :-( */ - data = rec_get_nth_field((rec_t*) rec, offsets, col_no, &len); + data = rec_get_nth_field(rec, offsets, col_no, &len); ut_a(len == 8); - ut_a(len == sizeof(doc_id)); - doc_id = (doc_id_t) mach_read_from_8(data); + ut_ad(8 == sizeof(doc_id)); + doc_id = static_cast<doc_id_t>(mach_read_from_8(data)); return(doc_id); } @@ -4876,7 +4924,7 @@ fts_get_doc_id_from_rec( Search the index specific cache for a particular FTS index. @return the index specific cache else NULL */ UNIV_INTERN -const fts_index_cache_t* +fts_index_cache_t* fts_find_index_cache( /*=================*/ const fts_cache_t* cache, /*!< in: cache to search */ @@ -4884,7 +4932,8 @@ fts_find_index_cache( { /* We cast away the const because our internal function, takes non-const cache arg and returns a non-const pointer. */ - return(fts_get_index_cache((fts_cache_t*) cache, index)); + return(static_cast<fts_index_cache_t*>( + fts_get_index_cache((fts_cache_t*) cache, index))); } /*********************************************************************//** @@ -4960,7 +5009,7 @@ fts_cache_append_deleted_doc_ids( { ulint i; - mutex_enter((mutex_t*) &cache->deleted_lock); + mutex_enter((ib_mutex_t*) &cache->deleted_lock); for (i = 0; i < ib_vector_size(cache->deleted_doc_ids); ++i) { fts_update_t* update; @@ -4971,7 +5020,7 @@ fts_cache_append_deleted_doc_ids( ib_vector_push(vector, &update->doc_id); } - mutex_exit((mutex_t*) &cache->deleted_lock); + mutex_exit((ib_mutex_t*) &cache->deleted_lock); } /*********************************************************************//** @@ -5043,11 +5092,11 @@ UNIV_INTERN void fts_add_doc_id_column( /*==================*/ - dict_table_t* table) /*!< in/out: Table with FTS index */ + dict_table_t* table, /*!< in/out: Table with FTS index */ + mem_heap_t* heap) /*!< in: temporary memory heap, or NULL */ { dict_mem_table_add_col( - table, - table->heap, + table, heap, FTS_DOC_ID_COL_NAME, DATA_INT, dtype_form_prtype( @@ -5069,7 +5118,7 @@ fts_update_doc_id( doc_id_t* next_doc_id) /*!< in/out: buffer for writing */ { doc_id_t doc_id; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; if (*next_doc_id) { doc_id = *next_doc_id; @@ -5236,13 +5285,12 @@ fts_savepoint_copy( ftt_dst = fts_trx_table_clone(*ftt_src); - rbt_insert(dst->tables, &ftt_dst->table->id, &ftt_dst); + rbt_insert(dst->tables, &ftt_dst, &ftt_dst); } } /*********************************************************************//** -Take a FTS savepoint. -@return DB_SUCCESS or error code */ +Take a FTS savepoint. */ UNIV_INTERN void fts_savepoint_take( @@ -5312,7 +5360,6 @@ fts_savepoint_release( const char* name) /*!< in: savepoint name */ { ulint i; - fts_savepoint_t* prev; ib_vector_t* savepoints; ulint top_of_stack = 0; @@ -5322,9 +5369,6 @@ fts_savepoint_release( ut_a(ib_vector_size(savepoints) > 0); - prev = static_cast<fts_savepoint_t*>( - ib_vector_get(savepoints, top_of_stack)); - /* Skip the implied savepoint (first element). */ for (i = 1; i < ib_vector_size(savepoints); ++i) { fts_savepoint_t* savepoint; @@ -5338,17 +5382,6 @@ fts_savepoint_release( we have to skip deleted/released entries. */ if (savepoint->name != NULL && strcmp(name, savepoint->name) == 0) { - - fts_savepoint_t* last; - fts_savepoint_t temp; - - last = static_cast<fts_savepoint_t*>( - ib_vector_last(savepoints)); - - /* Swap the entries. */ - memcpy(&temp, last, sizeof(temp)); - memcpy(last, prev, sizeof(*last)); - memcpy(prev, &temp, sizeof(prev)); break; /* Track the previous savepoint instance that will @@ -5357,8 +5390,6 @@ fts_savepoint_release( /* We need to delete all entries greater than this element. */ top_of_stack = i; - - prev = savepoint; } } @@ -5395,8 +5426,7 @@ fts_savepoint_release( } /**********************************************************************//** -Refresh last statement savepoint. -@return DB_SUCCESS or error code */ +Refresh last statement savepoint. */ UNIV_INTERN void fts_savepoint_laststmt_refresh( @@ -5588,7 +5618,7 @@ static ibool fts_is_aux_table_name( /*==================*/ - fts_sys_table_t*table, /*!< out: table info */ + fts_aux_table_t*table, /*!< out: table info */ const char* name, /*!< in: table name */ ulint len) /*!< in: length of table name */ { @@ -5614,7 +5644,6 @@ fts_is_aux_table_name( if (ptr != NULL && len > 20 && strncmp(ptr, "FTS_", 4) == 0) { ulint i; - /* Skip the prefix. */ ptr += 4; len -= 4; @@ -5689,7 +5718,7 @@ fts_read_tables( void* user_arg) /*!< in: pointer to ib_vector_t */ { int i; - fts_sys_table_t*table; + fts_aux_table_t*table; mem_heap_t* heap; ibool done = FALSE; ib_vector_t* tables = static_cast<ib_vector_t*>(user_arg); @@ -5701,7 +5730,7 @@ fts_read_tables( /* We will use this heap for allocating strings. */ heap = static_cast<mem_heap_t*>(tables->allocator->arg); - table = static_cast<fts_sys_table_t*>(ib_vector_push(tables, NULL)); + table = static_cast<fts_aux_table_t*>(ib_vector_push(tables, NULL)); memset(table, 0x0, sizeof(*table)); @@ -5726,9 +5755,9 @@ fts_read_tables( } table->name = static_cast<char*>( - mem_heap_dup(heap, data, len + 1)); - table->name[len] = '\0'; - printf("Found [%.*s]\n", (int) len, table->name); + mem_heap_alloc(heap, len + 1)); + memcpy(table->name, data, len); + table->name[len] = 0; break; case 1: /* ID */ @@ -5749,41 +5778,41 @@ fts_read_tables( Check and drop all orphaned FTS auxiliary tables, those that don't have a parent table or FTS index defined on them. @return DB_SUCCESS or error code */ -static -ulint +static __attribute__((nonnull)) +void fts_check_and_drop_orphaned_tables( /*===============================*/ trx_t* trx, /*!< in: transaction */ ib_vector_t* tables) /*!< in: tables to check */ { - ulint i; - ulint error = DB_SUCCESS; - - for (i = 0; i < ib_vector_size(tables); ++i) { + for (ulint i = 0; i < ib_vector_size(tables); ++i) { dict_table_t* table; - fts_sys_table_t* sys_table; - ibool drop = FALSE; + fts_aux_table_t* aux_table; + bool drop = false; - sys_table = static_cast<fts_sys_table_t*>( + aux_table = static_cast<fts_aux_table_t*>( ib_vector_get(tables, i)); - table = dict_table_open_on_id(sys_table->parent_id, FALSE); + table = dict_table_open_on_id( + aux_table->parent_id, TRUE, FALSE); if (table == NULL || table->fts == NULL) { - drop = TRUE; + drop = true; - } else if (sys_table->index_id != 0) { - ulint j; + } else if (aux_table->index_id != 0) { index_id_t id; - fts_t* fts; + fts_t* fts; - drop = TRUE; + drop = true; fts = table->fts; - id = sys_table->index_id; + id = aux_table->index_id; /* Search for the FT index in the table's list. */ - for (j = 0; j < ib_vector_size(fts->indexes); ++j) { + for (ulint j = 0; + j < ib_vector_size(fts->indexes); + ++j) { + const dict_index_t* index; index = static_cast<const dict_index_t*>( @@ -5791,28 +5820,36 @@ fts_check_and_drop_orphaned_tables( if (index->id == id) { - drop = FALSE; + drop = false; break; } } } if (table) { - dict_table_close(table, FALSE); + dict_table_close(table, TRUE, FALSE); } if (drop) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Warning: Parent table of " - "FT auxiliary table %s not found.\n", - sys_table->name); - /* We ignore drop errors. */ - fts_drop_table(trx, sys_table->name); + ib_logf(IB_LOG_LEVEL_WARN, + "Parent table of FTS auxiliary table %s not " + "found.", aux_table->name); + + dberr_t err = fts_drop_table(trx, aux_table->name); + + if (err == DB_FAIL) { + char* path; + + path = fil_make_ibd_name( + aux_table->name, false); + + os_file_delete_if_exists(path); + + mem_free(path); + } } } - - return(error); } /**********************************************************************//** @@ -5823,19 +5860,62 @@ void fts_drop_orphaned_tables(void) /*==========================*/ { - trx_t* trx; - pars_info_t* info; - mem_heap_t* heap; - que_t* graph; - ib_vector_t* tables; - ib_alloc_t* heap_alloc; - ulint error = DB_SUCCESS; + trx_t* trx; + pars_info_t* info; + mem_heap_t* heap; + que_t* graph; + ib_vector_t* tables; + ib_alloc_t* heap_alloc; + space_name_list_t space_name_list; + dberr_t error = DB_SUCCESS; + + /* Note: We have to free the memory after we are done with the list. */ + error = fil_get_space_names(space_name_list); + + if (error == DB_OUT_OF_MEMORY) { + ib_logf(IB_LOG_LEVEL_ERROR, "Out of memory"); + ut_error; + } heap = mem_heap_create(1024); heap_alloc = ib_heap_allocator_create(heap); /* We store the table ids of all the FTS indexes that were found. */ - tables = ib_vector_create(heap_alloc, sizeof(fts_sys_table_t), 128); + tables = ib_vector_create(heap_alloc, sizeof(fts_aux_table_t), 128); + + /* Get the list of all known .ibd files and check for orphaned + FTS auxiliary files in that list. We need to remove them because + users can't map them back to table names and this will create + unnecessary clutter. */ + + for (space_name_list_t::iterator it = space_name_list.begin(); + it != space_name_list.end(); + ++it) { + + fts_aux_table_t* fts_aux_table; + + fts_aux_table = static_cast<fts_aux_table_t*>( + ib_vector_push(tables, NULL)); + + memset(fts_aux_table, 0x0, sizeof(*fts_aux_table)); + + if (!fts_is_aux_table_name(fts_aux_table, *it, strlen(*it))) { + ib_vector_pop(tables); + } else { + ulint len = strlen(*it); + + fts_aux_table->id = fil_get_space_id_for_table(*it); + + /* We got this list from fil0fil.cc. The tablespace + with this name must exist. */ + ut_a(fts_aux_table->id != ULINT_UNDEFINED); + + fts_aux_table->name = static_cast<char*>( + mem_heap_dup(heap, *it, len + 1)); + + fts_aux_table->name[len] = 0; + } + } trx = trx_allocate_for_background(); trx->op_info = "dropping orphaned FTS tables"; @@ -5867,10 +5947,7 @@ fts_drop_orphaned_tables(void) error = fts_eval_sql(trx, graph); if (error == DB_SUCCESS) { - error = fts_check_and_drop_orphaned_tables(trx, tables); - } - - if (error == DB_SUCCESS) { + fts_check_and_drop_orphaned_tables(trx, tables); fts_sql_commit(trx); break; /* Exit the loop. */ } else { @@ -5881,15 +5958,15 @@ fts_drop_orphaned_tables(void) ut_print_timestamp(stderr); if (error == DB_LOCK_WAIT_TIMEOUT) { - fprintf(stderr, " InnoDB: Warning: lock wait " - "timeout reading SYS_TABLES. " - "Retrying!\n"); + ib_logf(IB_LOG_LEVEL_WARN, + "lock wait timeout reading SYS_TABLES. " + "Retrying!"); trx->error_state = DB_SUCCESS; } else { - fprintf(stderr, " InnoDB: Error: %lu " - "while reading SYS_TABLES.\n", - error); + ib_logf(IB_LOG_LEVEL_ERROR, + "(%s) while reading SYS_TABLES.", + ut_strerr(error)); break; /* Exit the loop. */ } @@ -5905,6 +5982,14 @@ fts_drop_orphaned_tables(void) if (heap != NULL) { mem_heap_free(heap); } + + /** Free the memory allocated to store the .ibd names. */ + for (space_name_list_t::iterator it = space_name_list.begin(); + it != space_name_list.end(); + ++it) { + + delete[] *it; + } } /**********************************************************************//** @@ -5986,7 +6071,7 @@ fts_load_stopword( { fts_table_t fts_table; fts_string_t str; - ulint error = DB_SUCCESS; + dberr_t error = DB_SUCCESS; ulint use_stopword; fts_cache_t* cache; const char* stopword_to_use = NULL; @@ -6086,6 +6171,43 @@ cleanup: /**********************************************************************//** Callback function when we initialize the FTS at the start up +time. It recovers the maximum Doc IDs presented in the current table. +@return: always returns TRUE */ +static +ibool +fts_init_get_doc_id( +/*================*/ + void* row, /*!< in: sel_node_t* */ + void* user_arg) /*!< in: fts cache */ +{ + doc_id_t doc_id = FTS_NULL_DOC_ID; + sel_node_t* node = static_cast<sel_node_t*>(row); + que_node_t* exp = node->select_list; + fts_cache_t* cache = static_cast<fts_cache_t*>(user_arg); + + ut_ad(ib_vector_is_empty(cache->get_docs)); + + /* Copy each indexed column content into doc->text.f_str */ + if (exp) { + dfield_t* dfield = que_node_get_val(exp); + dtype_t* type = dfield_get_type(dfield); + void* data = dfield_get_data(dfield); + + ut_a(dtype_get_mtype(type) == DATA_INT); + + doc_id = static_cast<doc_id_t>(mach_read_from_8( + static_cast<const byte*>(data))); + + if (doc_id >= cache->next_doc_id) { + cache->next_doc_id = doc_id + 1; + } + } + + return(TRUE); +} + +/**********************************************************************//** +Callback function when we initialize the FTS at the start up time. It recovers Doc IDs that have not sync-ed to the auxiliary table, and require to bring them back into FTS index. @return: always returns TRUE */ @@ -6100,22 +6222,16 @@ fts_init_recover_doc( fts_doc_t doc; ulint doc_len = 0; ulint field_no = 0; - ibool has_fts = TRUE; - fts_get_doc_t* get_doc = NULL; + fts_get_doc_t* get_doc = static_cast<fts_get_doc_t*>(user_arg); doc_id_t doc_id = FTS_NULL_DOC_ID; sel_node_t* node = static_cast<sel_node_t*>(row); que_node_t* exp = node->select_list; - fts_cache_t* cache = static_cast<fts_cache_t*>(user_arg); + fts_cache_t* cache = get_doc->cache; - if (ib_vector_is_empty(cache->get_docs)) { - has_fts = FALSE; - } else { - get_doc = static_cast<fts_get_doc_t*>( - ib_vector_get(cache->get_docs, 0)); + fts_doc_init(&doc); + doc.found = TRUE; - fts_doc_init(&doc); - doc.found = TRUE; - } + ut_ad(cache); /* Copy each indexed column content into doc->text.f_str */ while (exp) { @@ -6131,18 +6247,11 @@ fts_init_recover_doc( doc_id = static_cast<doc_id_t>(mach_read_from_8( static_cast<const byte*>(data))); - /* Just need to fetch the Doc ID */ - if (!has_fts) { - goto func_exit; - } - field_no++; exp = que_node_get_next(exp); continue; } - ut_a(has_fts); - if (len == UNIV_SQL_NULL) { exp = que_node_get_next(exp); continue; @@ -6196,7 +6305,6 @@ fts_init_recover_doc( cache->added++; -func_exit: if (doc_id >= cache->next_doc_id) { cache->next_doc_id = doc_id + 1; } @@ -6223,6 +6331,9 @@ fts_init_index( fts_get_doc_t* get_doc = NULL; ibool has_fts = TRUE; fts_cache_t* cache = table->fts->cache; + bool need_init = false; + + ut_ad(!mutex_own(&dict_sys->mutex)); /* First check cache->get_docs is initialized */ if (!has_cache_lock) { @@ -6239,6 +6350,8 @@ fts_init_index( goto func_exit; } + need_init = true; + start_doc = cache->synced_doc_id; if (!start_doc) { @@ -6250,28 +6363,32 @@ fts_init_index( dropped, and we re-initialize the Doc ID system for subsequent insertion */ if (ib_vector_is_empty(cache->get_docs)) { - index = dict_table_get_first_index(table); + index = dict_table_get_index_on_name(table, FTS_DOC_ID_INDEX_NAME); + + ut_a(index); + has_fts = FALSE; + fts_doc_fetch_by_doc_id(NULL, start_doc, index, + FTS_FETCH_DOC_BY_ID_LARGE, + fts_init_get_doc_id, cache); } else { - /* We only have one FTS index per table */ - get_doc = static_cast<fts_get_doc_t*>( - ib_vector_get(cache->get_docs, 0)); + for (ulint i = 0; i < ib_vector_size(cache->get_docs); ++i) { + get_doc = static_cast<fts_get_doc_t*>( + ib_vector_get(cache->get_docs, i)); - index = get_doc->index_cache->index; - } + index = get_doc->index_cache->index; - fts_doc_fetch_by_doc_id(NULL, start_doc, index, - FTS_FETCH_DOC_BY_ID_LARGE, - fts_init_recover_doc, cache); + fts_doc_fetch_by_doc_id(NULL, start_doc, index, + FTS_FETCH_DOC_BY_ID_LARGE, + fts_init_recover_doc, get_doc); + } + } if (has_fts) { if (table->fts->cache->stopword_info.status & STOPWORD_NOT_INIT) { fts_load_stopword(table, NULL, NULL, NULL, TRUE, TRUE); } - - /* Register the table with the optimize thread. */ - fts_optimize_add_table(table); } table->fts->fts_status |= ADDED_TABLE_SYNCED; @@ -6283,5 +6400,12 @@ func_exit: rw_lock_x_unlock(&cache->lock); } + if (need_init) { + mutex_enter(&dict_sys->mutex); + /* Register the table with the optimize thread. */ + fts_optimize_add_table(table); + mutex_exit(&dict_sys->mutex); + } + return(TRUE); } |