diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-10 08:02:21 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-10 08:02:21 +0300 |
commit | b2f3755c8e174ec5385c9a56783f0a77f054c562 (patch) | |
tree | bb00279f39334fb1a9afceca99da2c3179ec94df | |
parent | 136a27d9f16fd19f0196a798d752a3dcf0fe57c2 (diff) | |
parent | 3e8cab51cb78f3e60e139af944eef8f25502fc81 (diff) | |
download | mariadb-git-b2f3755c8e174ec5385c9a56783f0a77f054c562.tar.gz |
Merge 10.1 into 10.2
41 files changed, 851 insertions, 986 deletions
diff --git a/mysql-test/suite/innodb/r/foreign-keys.result b/mysql-test/suite/innodb/r/foreign-keys.result index 447013d408d..c4cf3a6a72d 100644 --- a/mysql-test/suite/innodb/r/foreign-keys.result +++ b/mysql-test/suite/innodb/r/foreign-keys.result @@ -100,6 +100,30 @@ CREATE TABLE t2 (b INT, KEY(b)) ENGINE=InnoDB; INSERT INTO t2 VALUES(2); ALTER TABLE t2 ADD FOREIGN KEY(b) REFERENCES t1(a), LOCK=EXCLUSIVE; DROP TABLE t2, t1; +# +# MDEV-16060 - InnoDB: Failing assertion: ut_strcmp(index->name, key->name) +# +CREATE TABLE t1 (`pk` INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +FLUSH TABLES; +SET debug_sync='alter_table_intermediate_table_created SIGNAL ready WAIT_FOR go'; +ALTER TABLE t1 ADD FOREIGN KEY(pk) REFERENCES t2(pk) ON UPDATE CASCADE; +connect con1, localhost, root; +SET debug_sync='now WAIT_FOR ready'; +SET lock_wait_timeout=1; +UPDATE t2 SET pk=10 WHERE pk=1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1'; +DEALLOCATE PREPARE stmt; +FLUSH TABLE t2; +SET debug_sync='now SIGNAL go'; +connection default; +disconnect con1; +connection default; +SET debug_sync='reset'; +SHOW OPEN TABLES FROM test; +Database Table In_use Name_locked +DROP TABLE t1, t2; create table t1 (a int primary key, b int) engine=innodb; create table t2 (c int primary key, d int, foreign key (d) references t1 (a) on update cascade) engine=innodb; diff --git a/mysql-test/suite/innodb/t/foreign-keys.test b/mysql-test/suite/innodb/t/foreign-keys.test index 442467b7dbe..be2c891771b 100644 --- a/mysql-test/suite/innodb/t/foreign-keys.test +++ b/mysql-test/suite/innodb/t/foreign-keys.test @@ -127,6 +127,38 @@ INSERT INTO t2 VALUES(2); ALTER TABLE t2 ADD FOREIGN KEY(b) REFERENCES t1(a), LOCK=EXCLUSIVE; DROP TABLE t2, t1; + +--echo # +--echo # MDEV-16060 - InnoDB: Failing assertion: ut_strcmp(index->name, key->name) +--echo # +CREATE TABLE t1 (`pk` INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 LIKE t1; +FLUSH TABLES; + +SET debug_sync='alter_table_intermediate_table_created SIGNAL ready WAIT_FOR go'; +send ALTER TABLE t1 ADD FOREIGN KEY(pk) REFERENCES t2(pk) ON UPDATE CASCADE; + +connect con1, localhost, root; +SET debug_sync='now WAIT_FOR ready'; +SET lock_wait_timeout=1; # change to 0 in 10.3 +--error ER_LOCK_WAIT_TIMEOUT +UPDATE t2 SET pk=10 WHERE pk=1; +PREPARE stmt FROM 'UPDATE t2 SET pk=10 WHERE pk=1'; +DEALLOCATE PREPARE stmt; +FLUSH TABLE t2; +SET debug_sync='now SIGNAL go'; + +connection default; +reap; + +# Cleanup +disconnect con1; + +connection default; +SET debug_sync='reset'; +SHOW OPEN TABLES FROM test; +DROP TABLE t1, t2; + # # FK and prelocking: # child table accesses (reads and writes) wait for locks. diff --git a/sql/mysql_upgrade_service.cc b/sql/mysql_upgrade_service.cc index 9bb60809205..ef01afe899d 100644 --- a/sql/mysql_upgrade_service.cc +++ b/sql/mysql_upgrade_service.cc @@ -148,8 +148,9 @@ static void die(const char *fmt, ...) #define WRITE_LOG(fmt,...) {\ char log_buf[1024]; \ + DWORD nbytes; \ snprintf(log_buf,sizeof(log_buf), fmt, __VA_ARGS__);\ - WriteFile(logfile_handle,log_buf, strlen(log_buf), 0 , 0);\ + WriteFile(logfile_handle,log_buf, strlen(log_buf), &nbytes , 0);\ } /* diff --git a/sql/mysqld.h b/sql/mysqld.h index b02bd9fb1f6..7177f0b2e20 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -66,7 +66,7 @@ typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */ #define OPT_SESSION SHOW_OPT_SESSION #define OPT_GLOBAL SHOW_OPT_GLOBAL -extern MY_TIMER_INFO sys_timer_info; +extern MYSQL_PLUGIN_IMPORT MY_TIMER_INFO sys_timer_info; /* Values for --slave-parallel-mode diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bb6945c7e01..e2c44fa9af3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, MariaDB + Copyright (c) 2010, 2019, MariaDB 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 @@ -8504,6 +8504,50 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, } } + /* + Normally, an attempt to modify an FK parent table will cause + FK children to be prelocked, so the table-being-altered cannot + be modified by a cascade FK action, because ALTER holds a lock + and prelocking will wait. + + But if a new FK is being added by this very ALTER, then the target + table is not locked yet (it's a temporary table). So, we have to + lock FK parents explicitly. + */ + if (alter_info->flags & Alter_info::ADD_FOREIGN_KEY) + { + List_iterator<Key> fk_list_it(alter_info->key_list); + + while (Key *key= fk_list_it++) + { + if (key->type != Key::FOREIGN_KEY) + continue; + + Foreign_key *fk= static_cast<Foreign_key*>(key); + char dbuf[NAME_LEN]; + char tbuf[NAME_LEN]; + const char *ref_db= fk->ref_db.str ? fk->ref_db.str : alter_ctx->new_db; + const char *ref_table= fk->ref_table.str; + MDL_request mdl_request; + + if (lower_case_table_names) + { + strmake_buf(dbuf, ref_db); + my_casedn_str(system_charset_info, dbuf); + strmake_buf(tbuf, ref_table); + my_casedn_str(system_charset_info, tbuf); + ref_db= dbuf; + ref_table= tbuf; + } + + mdl_request.init(MDL_key::TABLE, ref_db, ref_table, MDL_SHARED_NO_WRITE, + MDL_TRANSACTION); + if (thd->mdl_context.acquire_lock(&mdl_request, + thd->variables.lock_wait_timeout)) + DBUG_RETURN(true); + } + } + DBUG_RETURN(false); } @@ -9504,6 +9548,7 @@ do_continue:; /* Mark that we have created table in storage engine. */ no_ha_table= false; + DEBUG_SYNC(thd, "alter_table_intermediate_table_created"); new_table= thd->create_and_open_tmp_table(new_db_type, &frm, alter_ctx.get_tmp_path(), @@ -9517,54 +9562,6 @@ do_continue:; /* in case of alter temp table send the tracker in OK packet */ SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL); } - else - { - /* - Normally, an attempt to modify an FK parent table will cause - FK children to be prelocked, so the table-being-altered cannot - be modified by a cascade FK action, because ALTER holds a lock - and prelocking will wait. - - But if a new FK is being added by this very ALTER, then the target - table is not locked yet (it's a temporary table). So, we have to - lock FK parents explicitly. - */ - if (alter_info->flags & Alter_info::ADD_FOREIGN_KEY) - { - List <FOREIGN_KEY_INFO> fk_list; - List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list); - FOREIGN_KEY_INFO *fk; - - /* tables_opened can be > 1 only for MERGE tables */ - DBUG_ASSERT(tables_opened == 1); - DBUG_ASSERT(&table_list->next_global == thd->lex->query_tables_last); - - new_table->file->get_foreign_key_list(thd, &fk_list); - while ((fk= fk_list_it++)) - { - MDL_request mdl_request; - - if (lower_case_table_names) - { - char buf[NAME_LEN]; - uint len; - strmake_buf(buf, fk->referenced_db->str); - len = my_casedn_str(files_charset_info, buf); - thd->make_lex_string(fk->referenced_db, buf, len); - strmake_buf(buf, fk->referenced_table->str); - len = my_casedn_str(files_charset_info, buf); - thd->make_lex_string(fk->referenced_table, buf, len); - } - - mdl_request.init(MDL_key::TABLE, - fk->referenced_db->str, fk->referenced_table->str, - MDL_SHARED_NO_WRITE, MDL_TRANSACTION); - if (thd->mdl_context.acquire_lock(&mdl_request, - thd->variables.lock_wait_timeout)) - goto err_new_table_cleanup; - } - } - } /* Note: In case of MERGE table, we do not attach children. We do not diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 200a65ba6ef..0993b104c80 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -652,18 +652,13 @@ bad: ulint decomp = fil_page_decompress(buf, page); if (!decomp || (decomp != srv_page_size && page_size.is_compressed())) { - goto bad_doublewrite; + continue; } if (expect_encrypted && mach_read_from_4( page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) ? !fil_space_verify_crypt_checksum(page, page_size) : buf_page_is_corrupted(true, page, page_size, space)) { - if (!is_all_zero) { -bad_doublewrite: - ib::warn() << "A doublewrite copy of page " - << page_id << " is corrupted."; - } /* Theoretically we could have another good copy for this page in the doublewrite buffer. If not, we will report a fatal error diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 102d7e178b5..2d48fca35db 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2849,8 +2849,7 @@ but only by InnoDB table locks, which may be broken by lock_remove_all_on_table().) @param[in] table persistent table checked @return whether the table is accessible */ -bool -fil_table_accessible(const dict_table_t* table) +bool fil_table_accessible(const dict_table_t* table) { if (UNIV_UNLIKELY(!table->is_readable() || table->corrupted)) { return(false); diff --git a/storage/innobase/fts/fts0config.cc b/storage/innobase/fts/fts0config.cc index 7ad7459ea6a..c95689dbe98 100644 --- a/storage/innobase/fts/fts0config.cc +++ b/storage/innobase/fts/fts0config.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -215,8 +215,11 @@ fts_config_set_value( pars_info_bind_varchar_literal(info, "value", value->f_str, value->f_len); + const bool dict_locked = fts_table->table->fts->fts_status + & TABLE_DICT_LOCKED; + fts_table->suffix = "CONFIG"; - fts_get_table_name(fts_table, table_name); + fts_get_table_name(fts_table, table_name, dict_locked); pars_info_bind_id(info, true, "table_name", table_name); graph = fts_parse_sql( @@ -244,7 +247,7 @@ fts_config_set_value( pars_info_bind_varchar_literal( info, "value", value->f_str, value->f_len); - fts_get_table_name(fts_table, table_name); + fts_get_table_name(fts_table, table_name, dict_locked); pars_info_bind_id(info, true, "table_name", table_name); graph = fts_parse_sql( diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index a5e1d5eeb4c..57ee9a66c15 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -249,7 +249,6 @@ 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 */ MY_ATTRIBUTE((nonnull(1))); @@ -1532,14 +1531,13 @@ fts_rename_aux_tables( FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table); + dberr_t err = DB_SUCCESS; + char old_table_name[MAX_FULL_NAME_LEN]; + /* Rename common auxiliary tables */ for (i = 0; fts_common_tables[i] != NULL; ++i) { - char old_table_name[MAX_FULL_NAME_LEN]; - dberr_t err = DB_SUCCESS; - fts_table.suffix = fts_common_tables[i]; - - fts_get_table_name(&fts_table, old_table_name); + fts_get_table_name(&fts_table, old_table_name, true); err = fts_rename_one_aux_table(new_name, old_table_name, trx); @@ -1561,12 +1559,8 @@ fts_rename_aux_tables( FTS_INIT_INDEX_TABLE(&fts_table, NULL, FTS_INDEX_TABLE, index); for (ulint j = 0; j < FTS_NUM_AUX_INDEX; ++j) { - dberr_t err; - char old_table_name[MAX_FULL_NAME_LEN]; - fts_table.suffix = fts_get_suffix(j); - - fts_get_table_name(&fts_table, old_table_name); + fts_get_table_name(&fts_table, old_table_name, true); err = fts_rename_one_aux_table( new_name, old_table_name, trx); @@ -1605,8 +1599,7 @@ fts_drop_common_tables( char table_name[MAX_FULL_NAME_LEN]; fts_table->suffix = fts_common_tables[i]; - - fts_get_table_name(fts_table, table_name); + fts_get_table_name(fts_table, table_name, true); err = fts_drop_table(trx, table_name); @@ -1642,8 +1635,7 @@ fts_drop_index_split_tables( char table_name[MAX_FULL_NAME_LEN]; fts_table.suffix = fts_get_suffix(i); - - fts_get_table_name(&fts_table, table_name); + fts_get_table_name(&fts_table, table_name, true); err = fts_drop_table(trx, table_name); @@ -1890,7 +1882,7 @@ fts_create_common_tables( for (ulint i = 0; fts_common_tables[i] != NULL; ++i) { fts_table.suffix = fts_common_tables[i]; - fts_get_table_name(&fts_table, full_name[i]); + fts_get_table_name(&fts_table, full_name[i], true); dict_table_t* common_table = fts_create_one_common_table( trx, table, full_name[i], fts_table.suffix, heap); @@ -1915,7 +1907,7 @@ fts_create_common_tables( info = pars_info_create(); fts_table.suffix = "CONFIG"; - fts_get_table_name(&fts_table, fts_name); + fts_get_table_name(&fts_table, fts_name, true); pars_info_bind_id(info, true, "config_table", fts_name); graph = fts_parse_sql_no_dict_lock( @@ -1979,7 +1971,7 @@ fts_create_one_index_table( ut_ad(index->type & DICT_FTS); - fts_get_table_name(fts_table, table_name); + fts_get_table_name(fts_table, table_name, true); new_table = fts_create_in_mem_aux_table( table_name, fts_table->table, @@ -2068,7 +2060,6 @@ fts_create_index_tables_low( fts_table.type = FTS_INDEX_TABLE; fts_table.index_id = index->id; fts_table.table_id = table_id; - fts_table.parent = table_name; fts_table.table = index->table; /* aux_idx_tables vector is used for dropping FTS AUX INDEX @@ -2610,7 +2601,6 @@ 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, or NULL */ doc_id_t doc_id) /*!< in: DOC ID to set */ { table->fts->cache->synced_doc_id = doc_id; @@ -2619,7 +2609,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, trx); + table, table->fts->cache->synced_doc_id, trx); } @@ -2686,8 +2676,6 @@ retry: fts_table.type = FTS_COMMON_TABLE; fts_table.table = table; - fts_table.parent = table->name.m_name; - trx = trx_allocate_for_background(); if (srv_read_only_mode) { trx_start_internal_read_only(trx); @@ -2752,7 +2740,7 @@ retry: if (doc_id_cmp > *doc_id) { error = fts_update_sync_doc_id( - table, table->name.m_name, cache->synced_doc_id, trx); + table, cache->synced_doc_id, trx); } *doc_id = cache->next_doc_id; @@ -2788,7 +2776,6 @@ 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 */ { @@ -2810,11 +2797,6 @@ fts_update_sync_doc_id( fts_table.table_id = table->id; fts_table.type = FTS_COMMON_TABLE; fts_table.table = table; - if (table_name) { - fts_table.parent = table_name; - } else { - fts_table.parent = table->name.m_name; - } if (!trx) { trx = trx_allocate_for_background(); @@ -2831,7 +2813,8 @@ fts_update_sync_doc_id( pars_info_bind_varchar_literal(info, "doc_id", id, id_len); - fts_get_table_name(&fts_table, fts_name); + fts_get_table_name(&fts_table, fts_name, + table->fts->fts_status & TABLE_DICT_LOCKED); pars_info_bind_id(info, true, "table_name", fts_name); graph = fts_parse_sql( @@ -6243,7 +6226,6 @@ fts_rename_one_aux_table_to_hex_format( ut_a(fts_table.suffix != NULL); - fts_table.parent = parent_table->name.m_name; fts_table.table_id = aux_table->parent_id; fts_table.index_id = aux_table->index_id; fts_table.table = parent_table; diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 22efd3e27b0..2d39643f770 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -60,15 +60,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64; /** Last time we did check whether system need a sync */ static ib_time_t last_check_sync_time; -/** State of a table within the optimization sub system. */ -enum fts_state_t { - FTS_STATE_LOADED, - FTS_STATE_RUNNING, - FTS_STATE_SUSPENDED, - FTS_STATE_DONE, - FTS_STATE_EMPTY -}; - /** FTS optimize thread message types. */ enum fts_msg_type_t { FTS_MSG_STOP, /*!< Stop optimizing and exit thread */ @@ -177,11 +168,11 @@ struct fts_encode_t { /** We use this information to determine when to start the optimize cycle for a table. */ struct fts_slot_t { - dict_table_t* table; /*!< Table to optimize */ + /** table identifier, or 0 if the slot is empty */ + table_id_t table_id; - table_id_t table_id; /*!< Table id */ - - fts_state_t state; /*!< State of this slot */ + /** whether this slot is being processed */ + bool running; ulint added; /*!< Number of doc ids added since the last time this table was optimized */ @@ -1608,12 +1599,10 @@ fts_optimize_create( optim->trx = trx_allocate_for_background(); trx_start_internal(optim->trx); - optim->fts_common_table.parent = table->name.m_name; optim->fts_common_table.table_id = table->id; optim->fts_common_table.type = FTS_COMMON_TABLE; optim->fts_common_table.table = table; - optim->fts_index_table.parent = table->name.m_name; optim->fts_index_table.table_id = table->id; optim->fts_index_table.type = FTS_INDEX_TABLE; optim->fts_index_table.table = table; @@ -2392,31 +2381,35 @@ fts_optimize_table_bk( fts_slot_t* slot) /*!< in: table to optimiza */ { dberr_t error; - dict_table_t* table = slot->table; - fts_t* fts = table->fts; /* Avoid optimizing tables that were optimized recently. */ if (slot->last_run > 0 && (ut_time() - slot->last_run) < slot->interval_time) { return(DB_SUCCESS); + } - } else if (fts && fts->cache - && fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) { + dict_table_t* table = dict_table_open_on_id( + slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); + if (table && fil_table_accessible(table) + && table->fts && table->fts->cache + && table->fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) { error = fts_optimize_table(table); + slot->last_run = ut_time(); + if (error == DB_SUCCESS) { - slot->state = FTS_STATE_DONE; - slot->last_run = 0; - slot->completed = ut_time(); + slot->running = false; + slot->completed = slot->last_run; } } else { + /* Note time this run completed. */ + slot->last_run = ut_time(); error = DB_SUCCESS; } - /* Note time this run completed. */ - slot->last_run = ut_time(); + dict_table_close(table, FALSE, FALSE); return(error); } @@ -2633,85 +2626,59 @@ fts_optimize_request_sync_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap); } -/**********************************************************************//** -Add the table to the vector if it doesn't already exist. */ -static -ibool -fts_optimize_new_table( -/*===================*/ - ib_vector_t* tables, /*!< in/out: vector of tables */ - dict_table_t* table) /*!< in: table to add */ +/** Add a table to fts_slots if it doesn't already exist. */ +static bool fts_optimize_new_table(dict_table_t* table) { ulint i; fts_slot_t* slot; - ulint empty_slot = ULINT_UNDEFINED; + fts_slot_t* empty = NULL; + const table_id_t table_id = table->id; + ut_ad(table_id); /* Search for duplicates, also find a free slot if one exists. */ - for (i = 0; i < ib_vector_size(tables); ++i) { + for (i = 0; i < ib_vector_size(fts_slots); ++i) { - slot = static_cast<fts_slot_t*>( - ib_vector_get(tables, i)); + slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i)); - if (slot->state == FTS_STATE_EMPTY) { - empty_slot = i; - } else if (slot->table == table) { + if (!slot->table_id) { + empty = slot; + } else if (slot->table_id == table_id) { /* Already exists in our optimize queue. */ - ut_ad(slot->table_id == table->id); return(FALSE); } } - /* Reuse old slot. */ - if (empty_slot != ULINT_UNDEFINED) { - - slot = static_cast<fts_slot_t*>( - ib_vector_get(tables, empty_slot)); - - ut_a(slot->state == FTS_STATE_EMPTY); - - } else { /* Create a new slot. */ - - slot = static_cast<fts_slot_t*>(ib_vector_push(tables, NULL)); - } + slot = empty ? empty : static_cast<fts_slot_t*>( + ib_vector_push(fts_slots, NULL)); memset(slot, 0x0, sizeof(*slot)); - slot->table = table; slot->table_id = table->id; - slot->state = FTS_STATE_LOADED; + slot->running = false; slot->interval_time = FTS_OPTIMIZE_INTERVAL_IN_SECS; return(TRUE); } -/**********************************************************************//** -Remove the table from the vector if it exists. */ -static -ibool -fts_optimize_del_table( -/*===================*/ - ib_vector_t* tables, /*!< in/out: vector of tables */ - fts_msg_del_t* msg) /*!< in: table to delete */ +/** Remove a table from fts_slots if it exists. +@param[in,out] table table to be removed from fts_slots */ +static bool fts_optimize_del_table(const dict_table_t* table) { - ulint i; - dict_table_t* table = msg->table; + const table_id_t table_id = table->id; + ut_ad(table_id); - for (i = 0; i < ib_vector_size(tables); ++i) { + for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { fts_slot_t* slot; - slot = static_cast<fts_slot_t*>(ib_vector_get(tables, i)); - - if (slot->state != FTS_STATE_EMPTY - && slot->table == table) { + slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i)); + if (slot->table_id == table_id) { if (fts_enable_diag_print) { ib::info() << "FTS Optimize Removing table " << table->name; } - slot->table = NULL; - slot->state = FTS_STATE_EMPTY; - + slot->table_id = 0; return(TRUE); } } @@ -2720,14 +2687,9 @@ fts_optimize_del_table( } /**********************************************************************//** -Calculate how many of the registered tables need to be optimized. +Calculate how many tables in fts_slots need to be optimized. @return no. of tables to optimize */ -static -ulint -fts_optimize_how_many( -/*==================*/ - const ib_vector_t* tables) /*!< in: registered tables - vector*/ +static ulint fts_optimize_how_many() { ulint i; ib_time_t delta; @@ -2736,15 +2698,14 @@ fts_optimize_how_many( current_time = ut_time(); - for (i = 0; i < ib_vector_size(tables); ++i) { - const fts_slot_t* slot; - - slot = static_cast<const fts_slot_t*>( - ib_vector_get_const(tables, i)); + for (i = 0; i < ib_vector_size(fts_slots); ++i) { + const fts_slot_t* slot = static_cast<const fts_slot_t*>( + ib_vector_get_const(fts_slots, i)); + if (slot->table_id == 0) { + continue; + } - switch (slot->state) { - case FTS_STATE_DONE: - case FTS_STATE_LOADED: + if (!slot->running) { ut_a(slot->completed <= current_time); delta = current_time - slot->completed; @@ -2753,9 +2714,7 @@ fts_optimize_how_many( if (delta >= slot->interval_time) { ++n_tables; } - break; - - case FTS_STATE_RUNNING: + } else { ut_a(slot->last_run <= current_time); delta = current_time - slot->last_run; @@ -2763,15 +2722,7 @@ fts_optimize_how_many( if (delta > slot->interval_time) { ++n_tables; } - break; - - /* Slots in a state other than the above - are ignored. */ - case FTS_STATE_EMPTY: - case FTS_STATE_SUSPENDED: - break; } - } return(n_tables); @@ -2780,12 +2731,7 @@ fts_optimize_how_many( /**********************************************************************//** Check if the total memory used by all FTS table exceeds the maximum limit. @return true if a sync is needed, false otherwise */ -static -bool -fts_is_sync_needed( -/*===============*/ - const ib_vector_t* tables) /*!< in: registered tables - vector*/ +static bool fts_is_sync_needed() { ulint total_memory = 0; double time_diff = difftime(ut_time(), last_check_sync_time); @@ -2796,17 +2742,26 @@ fts_is_sync_needed( last_check_sync_time = ut_time(); - for (ulint i = 0; i < ib_vector_size(tables); ++i) { - const fts_slot_t* slot; + for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { + const fts_slot_t* slot = static_cast<const fts_slot_t*>( + ib_vector_get_const(fts_slots, i)); - slot = static_cast<const fts_slot_t*>( - ib_vector_get_const(tables, i)); + if (slot->table_id == 0) { + continue; + } + + dict_table_t* table = dict_table_open_on_id( + slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); + if (!table) { + continue; + } - if (slot->state != FTS_STATE_EMPTY && slot->table - && slot->table->fts && slot->table->fts->cache) { - total_memory += slot->table->fts->cache->total_size; + if (table->fts && table->fts->cache) { + total_memory += table->fts->cache->total_size; } + dict_table_close(table, FALSE, FALSE); + if (total_memory > fts_max_total_cache_size) { return(true); } @@ -2817,16 +2772,12 @@ fts_is_sync_needed( /** Sync fts cache of a table @param[in] table_id table id */ -void -fts_optimize_sync_table( - table_id_t table_id) +static void fts_optimize_sync_table(table_id_t table_id) { - dict_table_t* table = NULL; - - table = dict_table_open_on_id(table_id, FALSE, DICT_TABLE_OP_NORMAL); - - if (table) { - if (dict_table_has_fts_index(table) && table->fts->cache) { + if (dict_table_t* table = dict_table_open_on_id( + table_id, FALSE, DICT_TABLE_OP_NORMAL)) { + if (fil_table_accessible(table) + && table->fts && table->fts->cache) { fts_sync_table(table, true, false, false); } @@ -2866,28 +2817,18 @@ fts_optimize_thread( && ib_wqueue_is_empty(wq) && n_tables > 0 && n_optimize > 0) { - - fts_slot_t* slot; - - ut_a(ib_vector_size(fts_slots) > 0); - - slot = static_cast<fts_slot_t*>( + fts_slot_t* slot = static_cast<fts_slot_t*>( ib_vector_get(fts_slots, current)); /* Handle the case of empty slots. */ - if (slot->state != FTS_STATE_EMPTY) { - - slot->state = FTS_STATE_RUNNING; - + if (slot->table_id) { + slot->running = true; fts_optimize_table_bk(slot); } - ++current; - /* Wrap around the counter. */ - if (current >= ib_vector_size(fts_slots)) { - n_optimize = fts_optimize_how_many(fts_slots); - + if (++current >= ib_vector_size(fts_slots)) { + n_optimize = fts_optimize_how_many(); current = 0; } @@ -2899,7 +2840,7 @@ fts_optimize_thread( /* Timeout ? */ if (msg == NULL) { - if (fts_is_sync_needed(fts_slots)) { + if (fts_is_sync_needed()) { fts_need_sync = true; } @@ -2914,17 +2855,16 @@ fts_optimize_thread( case FTS_MSG_ADD_TABLE: ut_a(!done); if (fts_optimize_new_table( - fts_slots, - static_cast<dict_table_t*>( - msg->ptr))) { + static_cast<dict_table_t*>( + msg->ptr))) { ++n_tables; } break; case FTS_MSG_DEL_TABLE: if (fts_optimize_del_table( - fts_slots, static_cast<fts_msg_del_t*>( - msg->ptr))) { + static_cast<fts_msg_del_t*>( + msg->ptr)->table)) { --n_tables; } @@ -2948,33 +2888,25 @@ fts_optimize_thread( } mem_heap_free(msg->heap); - - if (!done) { - n_optimize = fts_optimize_how_many(fts_slots); - } else { - n_optimize = 0; - } + n_optimize = done ? 0 : fts_optimize_how_many(); } } /* Server is being shutdown, sync the data from FTS cache to disk if needed */ if (n_tables > 0) { - ulint i; - - for (i = 0; i < ib_vector_size(fts_slots); i++) { - fts_slot_t* slot; - - slot = static_cast<fts_slot_t*>( + for (ulint i = 0; i < ib_vector_size(fts_slots); i++) { + fts_slot_t* slot = static_cast<fts_slot_t*>( ib_vector_get(fts_slots, i)); - if (slot->state != FTS_STATE_EMPTY) { - fts_optimize_sync_table(slot->table_id); + if (table_id_t table_id = slot->table_id) { + fts_optimize_sync_table(table_id); } } } ib_vector_free(fts_slots); + fts_slots = NULL; ib::info() << "FTS optimize thread exiting."; @@ -3022,8 +2954,7 @@ fts_optimize_init(void) table = UT_LIST_GET_NEXT(table_LRU, table)) { if (table->fts && dict_table_has_fts_index(table)) { - if (fts_optimize_new_table(fts_slots, - table)){ + if (fts_optimize_new_table(table)){ table_vector.push_back(table); } } diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index 2396a376853..64504eeecf4 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -3961,7 +3961,6 @@ fts_query( query.fts_common_table.type = FTS_COMMON_TABLE; query.fts_common_table.table_id = index->table->id; - query.fts_common_table.parent = index->table->name.m_name; query.fts_common_table.table = index->table; charset = fts_index_get_charset(index); @@ -3969,7 +3968,6 @@ fts_query( query.fts_index_table.type = FTS_INDEX_TABLE; query.fts_index_table.index_id = index->id; query.fts_index_table.table_id = index->table->id; - query.fts_index_table.parent = index->table->name.m_name; query.fts_index_table.charset = charset; query.fts_index_table.table = index->table; diff --git a/storage/innobase/fts/fts0sql.cc b/storage/innobase/fts/fts0sql.cc index ae2186c2d30..bc39b28c983 100644 --- a/storage/innobase/fts/fts0sql.cc +++ b/storage/innobase/fts/fts0sql.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. 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 @@ -88,69 +89,52 @@ fts_get_table_id( return(len); } -/******************************************************************//** -Construct the prefix name of an FTS table. -@return own: table name, must be freed with ut_free() */ -char* -fts_get_table_name_prefix( -/*======================*/ - const fts_table_t* - fts_table) /*!< in: Auxiliary table type */ +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[in] dict_locked whether dict_sys->mutex is being held +@return the prefix, must be freed with ut_free() */ +char* fts_get_table_name_prefix(const fts_table_t* fts_table) { - int len; - const char* slash; - char* prefix_name; - int dbname_len = 0; - int prefix_name_len; char table_id[FTS_AUX_MIN_TABLE_ID_LENGTH]; - - slash = static_cast<const char*>( - memchr(fts_table->parent, '/', strlen(fts_table->parent))); - - if (slash) { - /* Print up to and including the separator. */ - dbname_len = static_cast<int>(slash - fts_table->parent) + 1; - } - - len = fts_get_table_id(fts_table, table_id); - - prefix_name_len = dbname_len + 4 + len + 1; - - prefix_name = static_cast<char*>(ut_malloc_nokey(prefix_name_len)); - - len = sprintf(prefix_name, "%.*sFTS_%s", - dbname_len, fts_table->parent, table_id); - - ut_a(len > 0); - ut_a(len == prefix_name_len - 1); - - return(prefix_name); + const size_t table_id_len = size_t(fts_get_table_id(fts_table, + table_id)) + 1; + mutex_enter(&dict_sys->mutex); + /* Include the separator as well. */ + const size_t dbname_len = fts_table->table->name.dblen() + 1; + ut_ad(dbname_len > 1); + const size_t prefix_name_len = dbname_len + 4 + table_id_len; + char* prefix_name = static_cast<char*>( + ut_malloc_nokey(prefix_name_len)); + memcpy(prefix_name, fts_table->table->name.m_name, dbname_len); + mutex_exit(&dict_sys->mutex); + memcpy(prefix_name + dbname_len, "FTS_", 4); + memcpy(prefix_name + dbname_len + 4, table_id, table_id_len); + return prefix_name; } -/******************************************************************//** -Construct the name of an ancillary FTS table for the given table. -Caller must allocate enough memory(usually size of MAX_FULL_NAME_LEN) -for param 'table_name'. */ -void -fts_get_table_name( -/*===============*/ - const fts_table_t* fts_table, - /*!< in: Auxiliary table type */ - char* table_name) - /*!< in/out: aux table name */ +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[out] table_name a name up to MAX_FULL_NAME_LEN +@param[in] dict_locked whether dict_sys->mutex is being held */ +void fts_get_table_name(const fts_table_t* fts_table, char* table_name, + bool dict_locked) { - int len; - char* prefix_name; - - prefix_name = fts_get_table_name_prefix(fts_table); - - len = sprintf(table_name, "%s_%s", prefix_name, fts_table->suffix); - - ut_a(len > 0); - ut_a(strlen(prefix_name) + 1 + strlen(fts_table->suffix) - == static_cast<uint>(len)); - - ut_free(prefix_name); + if (!dict_locked) { + mutex_enter(&dict_sys->mutex); + } + ut_ad(mutex_own(&dict_sys->mutex)); + /* Include the separator as well. */ + const size_t dbname_len = fts_table->table->name.dblen() + 1; + ut_ad(dbname_len > 1); + memcpy(table_name, fts_table->table->name.m_name, dbname_len); + if (!dict_locked) { + mutex_exit(&dict_sys->mutex); + } + memcpy(table_name += dbname_len, "FTS_", 4); + table_name += 4; + table_name += fts_get_table_id(fts_table, table_name); + *table_name++ = '_'; + strcpy(table_name, fts_table->suffix); } /******************************************************************//** @@ -205,14 +189,10 @@ fts_parse_sql_no_dict_lock( char* str; que_t* graph; -#ifdef UNIV_DEBUG ut_ad(mutex_own(&dict_sys->mutex)); -#endif str = ut_str3cat(fts_sql_begin, sql, fts_sql_end); - //fprintf(stderr, "%s\n", str); - graph = pars_sql(info, str); ut_a(graph); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index eb6664c427a..7c9d81cdd7f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -15101,6 +15101,10 @@ get_foreign_key_info( LEX_STRING* referenced_key_name; LEX_STRING* name = NULL; + if (dict_table_t::is_temporary_name(foreign->foreign_table_name)) { + return NULL; + } + ptr = dict_remove_db_name(foreign->id); f_key_info.foreign_id = thd_make_lex_string( thd, 0, ptr, strlen(ptr), 1); diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 0ef5e7a3364..8035b3b99b6 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -932,8 +932,7 @@ but only by InnoDB table locks, which may be broken by lock_remove_all_on_table().) @param[in] table persistent table checked @return whether the table is accessible */ -bool -fil_table_accessible(const dict_table_t* table) +bool fil_table_accessible(const dict_table_t* table) MY_ATTRIBUTE((warn_unused_result, nonnull)); /** Delete a tablespace and associated .ibd file. diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 82431c76b51..ef6865807eb 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2017, MariaDB Corporation. +Copyright (c) 2016, 2019, MariaDB Corporation. 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 @@ -176,7 +176,6 @@ do { \ (fts_table)->suffix = m_suffix; \ (fts_table)->type = m_type; \ (fts_table)->table_id = m_table->id; \ - (fts_table)->parent = m_table->name.m_name; \ (fts_table)->table = m_table; \ } while (0); @@ -185,7 +184,6 @@ do { \ (fts_table)->suffix = m_suffix; \ (fts_table)->type = m_type; \ (fts_table)->table_id = m_index->table->id; \ - (fts_table)->parent = m_index->table->name.m_name; \ (fts_table)->table = m_index->table; \ (fts_table)->index_id = m_index->id; \ } while (0); @@ -290,10 +288,6 @@ struct fts_result_t { table id and the index id to generate the column specific FTS auxiliary table name. */ struct fts_table_t { - const char* parent; /*!< Parent table name, this is - required only for the database - name */ - fts_table_type_t type; /*!< The auxiliary table type */ @@ -448,8 +442,8 @@ 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, or NULL */ - doc_id_t doc_id); /*!< in: DOC ID to set */ + doc_id_t doc_id) /*!< in: DOC ID to set */ + MY_ATTRIBUTE((nonnull(2))); /******************************************************************//** Create a new fts_doc_ids_t. diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h index 59e6311f7d4..45a50cd2938 100644 --- a/storage/innobase/include/fts0priv.h +++ b/storage/innobase/include/fts0priv.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -121,8 +121,7 @@ fts_parse_sql( fts_table_t* fts_table, /*!< in: FTS aux table */ pars_info_t* info, /*!< in: info struct, or NULL */ const char* sql) /*!< in: SQL string to evaluate */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull(3), malloc, warn_unused_result)); /******************************************************************//** Evaluate a parsed SQL statement @return DB_SUCCESS or error code */ @@ -131,19 +130,15 @@ fts_eval_sql( /*=========*/ trx_t* trx, /*!< in: transaction */ que_t* graph) /*!< in: Parsed statement */ - MY_ATTRIBUTE((warn_unused_result)); - -/******************************************************************//** -Construct the name of an ancillary FTS table for the given table. -Caller must allocate enough memory(usually size of MAX_FULL_NAME_LEN) -for param 'table_name'. */ -void -fts_get_table_name( -/*===============*/ - const fts_table_t* - fts_table, /*!< in: FTS aux table info */ - char* table_name); /*!< in/out: aux table name */ + MY_ATTRIBUTE((nonnull, warn_unused_result)); +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[out] table_name a name up to MAX_FULL_NAME_LEN +@param[in] dict_locked whether dict_sys->mutex is being held */ +void fts_get_table_name(const fts_table_t* fts_table, char* table_name, + bool dict_locked = false) + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Construct the column specification part of the SQL string for selecting the indexed FTS columns for the given table. Adds the necessary bound @@ -165,7 +160,7 @@ fts_get_select_columns_str( dict_index_t* index, /*!< in: FTS index */ pars_info_t* info, /*!< in/out: parser info */ mem_heap_t* heap) /*!< in: memory heap */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, warn_unused_result)); /** define for fts_doc_fetch_by_doc_id() "option" value, defines whether we want to get Doc whose ID is equal to or greater or smaller than supplied @@ -190,7 +185,8 @@ fts_doc_fetch_by_doc_id( fts_sql_callback callback, /*!< in: callback to read records */ - void* arg); /*!< in: callback arg */ + void* arg) /*!< in: callback arg */ + MY_ATTRIBUTE((nonnull(6))); /*******************************************************************//** Callback function for fetch that stores the text of an FTS document, @@ -200,8 +196,8 @@ ibool fts_query_expansion_fetch_doc( /*==========================*/ void* row, /*!< in: sel_node_t* */ - void* user_arg); /*!< in: fts_doc_t* */ - + void* user_arg) /*!< in: fts_doc_t* */ + MY_ATTRIBUTE((nonnull)); /******************************************************************** Write out a single word's data as new entry/entries in the INDEX table. @return DB_SUCCESS if all OK. */ @@ -213,7 +209,7 @@ fts_write_node( fts_table_t* fts_table, /*!< in: the FTS aux index */ fts_string_t* word, /*!< in: word in UTF-8 */ fts_node_t* node) /*!< in: node columns */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Check if a fts token is a stopword or less than fts_min_token_size or greater than fts_max_token_size. @@ -233,7 +229,8 @@ Initialize a document. */ void fts_doc_init( /*=========*/ - fts_doc_t* doc); /*!< in: doc to initialize */ + fts_doc_t* doc) /*!< in: doc to initialize */ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Do a binary search for a doc id in the array @@ -246,21 +243,21 @@ fts_bsearch( int lower, /*!< in: lower bound of array*/ int upper, /*!< in: upper bound of array*/ doc_id_t doc_id) /*!< in: doc id to lookup */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Free document. */ void fts_doc_free( /*=========*/ - fts_doc_t* doc); /*!< in: document */ - + fts_doc_t* doc) /*!< in: document */ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Free fts_optimizer_word_t instanace.*/ void fts_word_free( /*==========*/ - fts_word_t* word); /*!< in: instance to free.*/ - + fts_word_t* word) /*!< in: instance to free.*/ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Read the rows from the FTS inde @return DB_SUCCESS or error code */ @@ -272,8 +269,8 @@ fts_index_fetch_nodes( fts_table_t* fts_table, /*!< in: FTS aux table */ const fts_string_t* word, /*!< in: the word to fetch */ - fts_fetch_t* fetch); /*!< in: fetch callback.*/ - + fts_fetch_t* fetch) /*!< in: fetch callback.*/ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Compare two fts_trx_table_t instances, we actually compare the table id's here. @@ -283,8 +280,8 @@ int fts_trx_table_cmp( /*==============*/ const void* v1, /*!< in: id1 */ - const void* v2); /*!< in: id2 */ - + const void* v2) /*!< in: id2 */ + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Compare a table id with a trx_table_t table id. @return < 0 if n1 < n2, 0 if n1 == n2, > 0 if n1 > n2 */ @@ -293,24 +290,24 @@ int fts_trx_table_id_cmp( /*=================*/ const void* p1, /*!< in: id1 */ - const void* p2); /*!< in: id2 */ - + const void* p2) /*!< in: id2 */ + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Commit a transaction. @return DB_SUCCESS if all OK */ dberr_t fts_sql_commit( /*===========*/ - trx_t* trx); /*!< in: transaction */ - + trx_t* trx) /*!< in: transaction */ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Rollback a transaction. @return DB_SUCCESS if all OK */ dberr_t fts_sql_rollback( /*=============*/ - trx_t* trx); /*!< in: transaction */ - + trx_t* trx) /*!< in: transaction */ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Parse an SQL string. %s is replaced with the table's id. Don't acquire the dict mutex @@ -321,8 +318,7 @@ fts_parse_sql_no_dict_lock( fts_table_t* fts_table, /*!< in: table with FTS index */ pars_info_t* info, /*!< in: parser info */ const char* sql) /*!< in: SQL string to evaluate */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull(3), malloc, warn_unused_result)); /******************************************************************//** Get value from config table. The caller must ensure that enough space is allocated for value to hold the column contents @@ -334,8 +330,9 @@ fts_config_get_value( fts_table_t* fts_table, /*!< in: the indexed FTS table */ const char* name, /*!< in: get config value for this parameter name */ - fts_string_t* value); /*!< out: value read from + fts_string_t* value) /*!< out: value read from config table */ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Get value specific to an FTS index from the config table. The caller must ensure that enough space is allocated for value to hold the @@ -350,8 +347,7 @@ fts_config_get_index_value( this parameter name */ fts_string_t* value) /*!< out: value read from config table */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Set the value in the config table for name. @return DB_SUCCESS or error code */ @@ -363,8 +359,8 @@ fts_config_set_value( const char* name, /*!< in: get config value for this parameter name */ const fts_string_t* - value); /*!< in: value to update */ - + value) /*!< in: value to update */ + MY_ATTRIBUTE((nonnull)); /****************************************************************//** Set an ulint value in the config table. @return DB_SUCCESS if all OK else error code */ @@ -375,8 +371,7 @@ fts_config_set_ulint( fts_table_t* fts_table, /*!< in: the indexed FTS table */ const char* name, /*!< in: param name */ ulint int_value) /*!< in: value */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Set the value specific to an FTS index in the config table. @return DB_SUCCESS or error code */ @@ -389,7 +384,7 @@ fts_config_set_index_value( this parameter name */ fts_string_t* value) /*!< out: value read from config table */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, warn_unused_result)); #ifdef FTS_OPTIMIZE_DEBUG /******************************************************************//** @@ -402,7 +397,7 @@ fts_config_get_index_ulint( dict_index_t* index, /*!< in: FTS index */ const char* name, /*!< in: param name */ ulint* int_value) /*!< out: value */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, warn_unused_result)); #endif /* FTS_OPTIMIZE_DEBUG */ /******************************************************************//** @@ -415,8 +410,7 @@ fts_config_set_index_ulint( dict_index_t* index, /*!< in: FTS index */ const char* name, /*!< in: param name */ ulint int_value) /*!< in: value */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Get an ulint value from the config table. @return DB_SUCCESS or error code */ @@ -426,8 +420,8 @@ fts_config_get_ulint( trx_t* trx, /*!< in: transaction */ fts_table_t* fts_table, /*!< in: the indexed FTS table */ const char* name, /*!< in: param name */ - ulint* int_value); /*!< out: value */ - + ulint* int_value) /*!< out: value */ + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Search cache for word. @return the word node vector if found else NULL */ @@ -438,7 +432,7 @@ fts_cache_find_word( index_cache, /*!< in: cache to search */ const fts_string_t* text) /*!< in: word to search for */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Append deleted doc ids to vector and sort the vector. */ @@ -471,8 +465,7 @@ fts_find_index_cache( cache, /*!< in: cache to search */ const dict_index_t* index) /*!< in: index to search for */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Write the table id to the given buffer (including final NUL). Buffer must be at least FTS_AUX_MIN_TABLE_ID_LENGTH bytes long. @@ -483,10 +476,10 @@ fts_write_object_id( /*================*/ ib_id_t id, /*!< in: a table/index id */ char* str, /*!< in: buffer to write the id to */ - bool hex_format MY_ATTRIBUTE((unused))); + bool hex_format MY_ATTRIBUTE((unused))) /*!< in: true for fixed hex format, false for old ambiguous format */ - + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Read the table id from the string generated by fts_write_object_id(). @return TRUE if parse successful */ @@ -496,8 +489,7 @@ fts_read_object_id( /*===============*/ ib_id_t* id, /*!< out: a table id */ const char* str) /*!< in: buffer to read from */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull, warn_unused_result)); /******************************************************************//** Get the table id. @return number of bytes written */ @@ -509,18 +501,13 @@ fts_get_table_id( char* table_id) /*!< out: table id, must be at least FTS_AUX_MIN_TABLE_ID_LENGTH bytes long */ - MY_ATTRIBUTE((warn_unused_result)); - -/******************************************************************//** -Construct the prefix name of an FTS table. -@return own: table name, must be freed with ut_free() */ -char* -fts_get_table_name_prefix( -/*======================*/ - const fts_table_t* - fts_table) /*!< in: Auxiliary table type */ - MY_ATTRIBUTE((warn_unused_result)); - + MY_ATTRIBUTE((nonnull, warn_unused_result)); +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[in] dict_locked whether dict_sys->mutex is being held +@return the prefix, must be freed with ut_free() */ +char* fts_get_table_name_prefix(const fts_table_t* fts_table) + MY_ATTRIBUTE((nonnull, malloc, warn_unused_result)); /******************************************************************//** Add node positions. */ void @@ -529,7 +516,8 @@ fts_cache_node_add_positions( fts_cache_t* cache, /*!< in: cache */ fts_node_t* node, /*!< in: word node */ doc_id_t doc_id, /*!< in: doc id */ - ib_vector_t* positions); /*!< in: fts_token_t::positions */ + ib_vector_t* positions) /*!< in: fts_token_t::positions */ + MY_ATTRIBUTE((nonnull(2,4))); /******************************************************************//** Create the config table name for retrieving index specific value. @@ -539,7 +527,7 @@ fts_config_create_index_param_name( /*===============================*/ const char* param, /*!< in: base name of param */ const dict_index_t* index) /*!< in: index for config */ - MY_ATTRIBUTE((warn_unused_result)); + MY_ATTRIBUTE((nonnull, malloc, warn_unused_result)); #include "fts0priv.ic" diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index d3af57986de..4049d467961 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -1655,7 +1655,6 @@ row_fts_merge_insert( fts_table.type = FTS_INDEX_TABLE; fts_table.index_id = index->id; fts_table.table_id = table->id; - fts_table.parent = index->table->name.m_name; fts_table.table = index->table; fts_table.suffix = fts_get_suffix(id); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index e1ef6983073..10600468e5a 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -2736,9 +2736,7 @@ wait_again: false, true, false); if (err == DB_SUCCESS) { - fts_update_next_doc_id( - 0, new_table, - old_table->name.m_name, max_doc_id); + fts_update_next_doc_id(NULL, new_table, max_doc_id); } } diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc index cffcc73f312..e7230b1f929 100644 --- a/storage/innobase/row/row0trunc.cc +++ b/storage/innobase/row/row0trunc.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -1531,7 +1531,7 @@ row_truncate_update_system_tables( os_thread_sleep(10000000);); table->fts->fts_status |= TABLE_DICT_LOCKED; - fts_update_next_doc_id(trx, table, NULL, 0); + fts_update_next_doc_id(trx, table, 0); fts_cache_clear(table->fts->cache); fts_cache_init(table->fts->cache); table->fts->fts_status &= uint(~TABLE_DICT_LOCKED); diff --git a/storage/innobase/ut/ut0timer.cc b/storage/innobase/ut/ut0timer.cc index 85292cce28c..abb2326d8a5 100644 --- a/storage/innobase/ut/ut0timer.cc +++ b/storage/innobase/ut/ut0timer.cc @@ -46,6 +46,7 @@ Function pointer to point selected timer function. ulonglong (*ut_timer_now)(void) = &ut_timer_none; struct my_timer_unit_info ut_timer; +extern MYSQL_PLUGIN_IMPORT MY_TIMER_INFO sys_timer_info; /**************************************************************//** Sets up the data required for use of my_timer_* functions. @@ -57,30 +58,27 @@ void ut_init_timer(void) /*===============*/ { - MY_TIMER_INFO all_timer_info; - my_timer_init(&all_timer_info); - - if (all_timer_info.cycles.frequency > 1000000 && - all_timer_info.cycles.resolution == 1) { - ut_timer = all_timer_info.cycles; + if (sys_timer_info.cycles.frequency > 1000000 && + sys_timer_info.cycles.resolution == 1) { + ut_timer = sys_timer_info.cycles; ut_timer_now = &my_timer_cycles; - } else if (all_timer_info.nanoseconds.frequency > 1000000 && - all_timer_info.nanoseconds.resolution == 1) { - ut_timer = all_timer_info.nanoseconds; + } else if (sys_timer_info.nanoseconds.frequency > 1000000 && + sys_timer_info.nanoseconds.resolution == 1) { + ut_timer = sys_timer_info.nanoseconds; ut_timer_now = &my_timer_nanoseconds; - } else if (all_timer_info.microseconds.frequency >= 1000000 && - all_timer_info.microseconds.resolution == 1) { - ut_timer = all_timer_info.microseconds; + } else if (sys_timer_info.microseconds.frequency >= 1000000 && + sys_timer_info.microseconds.resolution == 1) { + ut_timer = sys_timer_info.microseconds; ut_timer_now = &my_timer_microseconds; - } else if (all_timer_info.milliseconds.frequency >= 1000 && - all_timer_info.milliseconds.resolution == 1) { - ut_timer = all_timer_info.milliseconds; + } else if (sys_timer_info.milliseconds.frequency >= 1000 && + sys_timer_info.milliseconds.resolution == 1) { + ut_timer = sys_timer_info.milliseconds; ut_timer_now = &my_timer_milliseconds; - } else if (all_timer_info.ticks.frequency >= 1000 && + } else if (sys_timer_info.ticks.frequency >= 1000 && /* Will probably be false */ - all_timer_info.ticks.resolution == 1) { - ut_timer = all_timer_info.ticks; + sys_timer_info.ticks.resolution == 1) { + ut_timer = sys_timer_info.ticks; ut_timer_now = &my_timer_ticks; } else { /* None are acceptable, so leave it as "None", and fill in struct */ diff --git a/storage/perfschema/pfs_timer.cc b/storage/perfschema/pfs_timer.cc index 8348f165e5c..cc99e69c3cc 100644 --- a/storage/perfschema/pfs_timer.cc +++ b/storage/perfschema/pfs_timer.cc @@ -26,7 +26,6 @@ enum_timer_name idle_timer= TIMER_NAME_MICROSEC; enum_timer_name wait_timer= TIMER_NAME_CYCLE; enum_timer_name stage_timer= TIMER_NAME_NANOSEC; enum_timer_name statement_timer= TIMER_NAME_NANOSEC; -MY_TIMER_INFO pfs_timer_info; static ulonglong cycle_v0; static ulonglong nanosec_v0; @@ -65,41 +64,39 @@ void init_timers(void) { double pico_frequency= 1.0e12; - my_timer_init(&pfs_timer_info); - cycle_v0= my_timer_cycles(); nanosec_v0= my_timer_nanoseconds(); microsec_v0= my_timer_microseconds(); millisec_v0= my_timer_milliseconds(); tick_v0= my_timer_ticks(); - if (pfs_timer_info.cycles.frequency > 0) + if (sys_timer_info.cycles.frequency > 0) cycle_to_pico= round_to_ulong(pico_frequency/ - (double)pfs_timer_info.cycles.frequency); + (double)sys_timer_info.cycles.frequency); else cycle_to_pico= 0; - if (pfs_timer_info.nanoseconds.frequency > 0) + if (sys_timer_info.nanoseconds.frequency > 0) nanosec_to_pico= round_to_ulong(pico_frequency/ - (double)pfs_timer_info.nanoseconds.frequency); + (double)sys_timer_info.nanoseconds.frequency); else nanosec_to_pico= 0; - if (pfs_timer_info.microseconds.frequency > 0) + if (sys_timer_info.microseconds.frequency > 0) microsec_to_pico= round_to_ulong(pico_frequency/ - (double)pfs_timer_info.microseconds.frequency); + (double)sys_timer_info.microseconds.frequency); else microsec_to_pico= 0; - if (pfs_timer_info.milliseconds.frequency > 0) + if (sys_timer_info.milliseconds.frequency > 0) millisec_to_pico= round_to_ulong(pico_frequency/ - (double)pfs_timer_info.milliseconds.frequency); + (double)sys_timer_info.milliseconds.frequency); else millisec_to_pico= 0; - if (pfs_timer_info.ticks.frequency > 0) + if (sys_timer_info.ticks.frequency > 0) tick_to_pico= round_to_ulonglong(pico_frequency/ - (double)pfs_timer_info.ticks.frequency); + (double)sys_timer_info.ticks.frequency); else tick_to_pico= 0; diff --git a/storage/perfschema/pfs_timer.h b/storage/perfschema/pfs_timer.h index 1cae20e89dd..1b167a46dad 100644 --- a/storage/perfschema/pfs_timer.h +++ b/storage/perfschema/pfs_timer.h @@ -102,7 +102,7 @@ extern enum_timer_name statement_timer; Timer information data. Characteristics about each suported timer. */ -extern MY_TIMER_INFO pfs_timer_info; +extern MYSQL_PLUGIN_IMPORT MY_TIMER_INFO sys_timer_info; /** Initialize the timer component. */ void init_timers(); diff --git a/storage/perfschema/table_performance_timers.cc b/storage/perfschema/table_performance_timers.cc index 780d507a64b..dc36874d6e9 100644 --- a/storage/perfschema/table_performance_timers.cc +++ b/storage/perfschema/table_performance_timers.cc @@ -58,23 +58,23 @@ table_performance_timers::table_performance_timers() index= (int)TIMER_NAME_CYCLE - FIRST_TIMER_NAME; m_data[index].m_timer_name= TIMER_NAME_CYCLE; - m_data[index].m_info= pfs_timer_info.cycles; + m_data[index].m_info= sys_timer_info.cycles; index= (int)TIMER_NAME_NANOSEC - FIRST_TIMER_NAME; m_data[index].m_timer_name= TIMER_NAME_NANOSEC; - m_data[index].m_info= pfs_timer_info.nanoseconds; + m_data[index].m_info= sys_timer_info.nanoseconds; index= (int)TIMER_NAME_MICROSEC - FIRST_TIMER_NAME; m_data[index].m_timer_name= TIMER_NAME_MICROSEC; - m_data[index].m_info= pfs_timer_info.microseconds; + m_data[index].m_info= sys_timer_info.microseconds; index= (int)TIMER_NAME_MILLISEC - FIRST_TIMER_NAME; m_data[index].m_timer_name= TIMER_NAME_MILLISEC; - m_data[index].m_info= pfs_timer_info.milliseconds; + m_data[index].m_info= sys_timer_info.milliseconds; index= (int)TIMER_NAME_TICK - FIRST_TIMER_NAME; m_data[index].m_timer_name= TIMER_NAME_TICK; - m_data[index].m_info= pfs_timer_info.ticks; + m_data[index].m_info= sys_timer_info.ticks; } void table_performance_timers::reset_position(void) diff --git a/storage/perfschema/unittest/pfs_server_stubs.cc b/storage/perfschema/unittest/pfs_server_stubs.cc index d7154067fc2..1093b6a859b 100644 --- a/storage/perfschema/unittest/pfs_server_stubs.cc +++ b/storage/perfschema/unittest/pfs_server_stubs.cc @@ -43,3 +43,5 @@ enum sys_var::where get_sys_var_value_origin(void *ptr) { return sys_var::AUTO; } + +MY_TIMER_INFO sys_timer_info; diff --git a/storage/perfschema/unittest/pfs_timer-t.cc b/storage/perfschema/unittest/pfs_timer-t.cc index 55113860532..f2752191447 100644 --- a/storage/perfschema/unittest/pfs_timer-t.cc +++ b/storage/perfschema/unittest/pfs_timer-t.cc @@ -33,6 +33,8 @@ void test_timers() ulonglong t4_b; ulonglong t5_b; + my_timer_init(&sys_timer_info); + init_timers(); t1_a= get_timer_pico_value(TIMER_NAME_CYCLE); diff --git a/storage/xtradb/buf/buf0dblwr.cc b/storage/xtradb/buf/buf0dblwr.cc index a22395bcc3e..c68d10ae0b0 100644 --- a/storage/xtradb/buf/buf0dblwr.cc +++ b/storage/xtradb/buf/buf0dblwr.cc @@ -612,20 +612,13 @@ bad: ulint decomp = fil_page_decompress(buf, page); if (!decomp || (decomp != srv_page_size && zip_size)) { - goto bad_doublewrite; + continue; } if (expect_encrypted && mach_read_from_4( page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) ? !fil_space_verify_crypt_checksum(page, zip_size) : buf_page_is_corrupted(true, page, zip_size, space())) { - if (!is_all_zero) { -bad_doublewrite: - ib_logf(IB_LOG_LEVEL_WARN, - "A doublewrite copy of page " - ULINTPF ":" ULINTPF " is corrupted.", - space_id, page_no); - } /* Theoretically we could have another good copy for this page in the doublewrite buffer. If not, we will report a fatal error diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 690b4c8df8b..8f25488649f 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -2819,6 +2819,29 @@ fil_close_tablespace( return(err); } +/** Determine whether a table can be accessed in operations that are +not (necessarily) protected by meta-data locks. +(Rollback would generally be protected, but rollback of +FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks +but only by InnoDB table locks, which may be broken by +lock_remove_all_on_table().) +@param[in] table persistent table +checked @return whether the table is accessible */ +UNIV_INTERN bool fil_table_accessible(const dict_table_t* table) +{ + if (UNIV_UNLIKELY(!table->is_readable() || table->corrupted)) { + return(false); + } + + if (fil_space_t* space = fil_space_acquire(table->space)) { + bool accessible = !space->is_stopping(); + fil_space_release(space); + return(accessible); + } else { + return(false); + } +} + /** Delete a tablespace and associated .ibd file. @param[in] id tablespace identifier @param[in] drop_ahi whether to drop the adaptive hash index diff --git a/storage/xtradb/fts/fts0config.cc b/storage/xtradb/fts/fts0config.cc index 5b4ae5c39f7..bcf7d7581da 100644 --- a/storage/xtradb/fts/fts0config.cc +++ b/storage/xtradb/fts/fts0config.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -85,6 +86,7 @@ fts_config_get_value( que_t* graph; dberr_t error; ulint name_len = strlen(name); + char table_name[MAX_FULL_NAME_LEN]; info = pars_info_create(); @@ -100,12 +102,14 @@ fts_config_get_value( pars_info_bind_varchar_literal(info, "name", (byte*) name, name_len); fts_table->suffix = "CONFIG"; + fts_get_table_name(fts_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); graph = fts_parse_sql( fts_table, info, "DECLARE FUNCTION my_func;\n" - "DECLARE CURSOR c IS SELECT value FROM \"%s\"" + "DECLARE CURSOR c IS SELECT value FROM $table_name" " WHERE key = :name;\n" "BEGIN\n" "" @@ -212,6 +216,7 @@ fts_config_set_value( undo_no_t undo_no; undo_no_t n_rows_updated; ulint name_len = strlen(name); + char table_name[MAX_FULL_NAME_LEN]; info = pars_info_create(); @@ -219,11 +224,17 @@ fts_config_set_value( pars_info_bind_varchar_literal(info, "value", value->f_str, value->f_len); + const bool dict_locked = fts_table->table->fts->fts_status + & TABLE_DICT_LOCKED; + fts_table->suffix = "CONFIG"; + fts_get_table_name(fts_table, table_name, dict_locked); + pars_info_bind_id(info, true, "table_name", table_name); graph = fts_parse_sql( fts_table, info, - "BEGIN UPDATE \"%s\" SET value = :value WHERE key = :name;"); + "BEGIN UPDATE $table_name SET value = :value " + "WHERE key = :name;"); trx->op_info = "setting FTS config value"; @@ -245,10 +256,13 @@ fts_config_set_value( pars_info_bind_varchar_literal( info, "value", value->f_str, value->f_len); + fts_get_table_name(fts_table, table_name, dict_locked); + pars_info_bind_id(info, true, "table_name", table_name); + graph = fts_parse_sql( fts_table, info, "BEGIN\n" - "INSERT INTO \"%s\" VALUES(:name, :value);"); + "INSERT INTO $table_name VALUES(:name, :value);"); trx->op_info = "inserting FTS config value"; @@ -465,6 +479,7 @@ fts_config_increment_value( que_t* graph = NULL; ulint name_len = strlen(name); pars_info_t* info = pars_info_create(); + char table_name[MAX_FULL_NAME_LEN]; /* We set the length of value to the max bytes it can hold. This information is used by the callback that reads the value.*/ @@ -479,11 +494,13 @@ fts_config_increment_value( info, "my_func", fts_config_fetch_value, &value); fts_table->suffix = "CONFIG"; + fts_get_table_name(fts_table, table_name); + pars_info_bind_id(info, true, "config_table", table_name); graph = fts_parse_sql( fts_table, info, "DECLARE FUNCTION my_func;\n" - "DECLARE CURSOR c IS SELECT value FROM \"%s\"" + "DECLARE CURSOR c IS SELECT value FROM $config_table" " WHERE key = :name FOR UPDATE;\n" "BEGIN\n" "" diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index 1ea3a8d2c60..57c232fce9c 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -167,38 +167,39 @@ struct fts_aux_table_t { char* name; /*!< Name of the table */ }; -/** SQL statements for creating the ancillary common FTS tables. */ +/** SQL statements for creating the ancillary common FTS tables. +The table name here shall be consistent with fts_common_tables. */ static const char* fts_create_common_tables_sql = { "BEGIN\n" "" - "CREATE TABLE \"%s_DELETED\" (\n" + "CREATE TABLE $DELETED (\n" " doc_id BIGINT UNSIGNED\n" ") COMPACT;\n" - "CREATE UNIQUE CLUSTERED INDEX IND ON \"%s_DELETED\"(doc_id);\n" + "CREATE UNIQUE CLUSTERED INDEX IND ON $DELETED (doc_id);\n" "" - "CREATE TABLE \"%s_DELETED_CACHE\" (\n" + "CREATE TABLE $DELETED_CACHE (\n" " doc_id BIGINT UNSIGNED\n" ") COMPACT;\n" "CREATE UNIQUE CLUSTERED INDEX IND " - "ON \"%s_DELETED_CACHE\"(doc_id);\n" + "ON $DELETED_CACHE(doc_id);\n" "" - "CREATE TABLE \"%s_BEING_DELETED\" (\n" + "CREATE TABLE $BEING_DELETED (\n" " doc_id BIGINT UNSIGNED\n" ") COMPACT;\n" "CREATE UNIQUE CLUSTERED INDEX IND " - "ON \"%s_BEING_DELETED\"(doc_id);\n" + "ON $BEING_DELETED(doc_id);\n" "" - "CREATE TABLE \"%s_BEING_DELETED_CACHE\" (\n" + "CREATE TABLE $BEING_DELETED_CACHE (\n" " doc_id BIGINT UNSIGNED\n" ") COMPACT;\n" "CREATE UNIQUE CLUSTERED INDEX IND " - "ON \"%s_BEING_DELETED_CACHE\"(doc_id);\n" + "ON $BEING_DELETED_CACHE(doc_id);\n" "" - "CREATE TABLE \"%s_CONFIG\" (\n" + "CREATE TABLE $CONFIG (\n" " key CHAR(50),\n" " value CHAR(200) NOT NULL\n" ") COMPACT;\n" - "CREATE UNIQUE CLUSTERED INDEX IND ON \"%s_CONFIG\"(key);\n" + "CREATE UNIQUE CLUSTERED INDEX IND ON $CONFIG(key);\n" }; #ifdef FTS_DOC_STATS_DEBUG @@ -207,11 +208,11 @@ mainly designed for the statistics work in the future */ static const char* fts_create_index_tables_sql = { "BEGIN\n" "" - "CREATE TABLE \"%s_DOC_ID\" (\n" + "CREATE TABLE $doc_id_table (\n" " doc_id BIGINT UNSIGNED,\n" " word_count INTEGER UNSIGNED NOT NULL\n" ") COMPACT;\n" - "CREATE UNIQUE CLUSTERED INDEX IND ON \"%s_DOC_ID\"(doc_id);\n" + "CREATE UNIQUE CLUSTERED INDEX IND ON $doc_id_table(doc_id);\n" }; #endif @@ -220,11 +221,11 @@ static const char* fts_create_index_sql = { "BEGIN\n" "" "CREATE UNIQUE CLUSTERED INDEX FTS_INDEX_TABLE_IND " - "ON \"%s\"(word, first_doc_id);\n" + "ON $table (word, first_doc_id);\n" }; /** FTS auxiliary table suffixes that are common to all FT indexes. */ -static const char* fts_common_tables[] = { +const char* fts_common_tables[] = { "BEING_DELETED", "BEING_DELETED_CACHE", "CONFIG", @@ -248,19 +249,19 @@ const fts_index_selector_t fts_index_selector[] = { static const char* fts_config_table_insert_values_sql = "BEGIN\n" "\n" - "INSERT INTO \"%s\" VALUES('" + "INSERT INTO $config_table VALUES('" FTS_MAX_CACHE_SIZE_IN_MB "', '256');\n" "" - "INSERT INTO \"%s\" VALUES('" + "INSERT INTO $config_table VALUES('" FTS_OPTIMIZE_LIMIT_IN_SECS "', '180');\n" "" - "INSERT INTO \"%s\" VALUES ('" + "INSERT INTO $config_table VALUES ('" FTS_SYNCED_DOC_ID "', '0');\n" "" - "INSERT INTO \"%s\" VALUES ('" + "INSERT INTO $config_table VALUES ('" FTS_TOTAL_DELETED_COUNT "', '0');\n" "" /* Note: 0 == FTS_TABLE_STATE_RUNNING */ - "INSERT INTO \"%s\" VALUES ('" + "INSERT INTO $config_table VALUES ('" FTS_TABLE_STATE "', '0');\n"; /** Run SYNC on the table, i.e., write out data from the cache to the @@ -334,7 +335,6 @@ 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 */ MY_ATTRIBUTE((nonnull(1))); @@ -1586,19 +1586,17 @@ fts_rename_aux_tables( FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table); + dberr_t err = DB_SUCCESS; + char old_table_name[MAX_FULL_NAME_LEN]; + /* Rename common auxiliary tables */ for (i = 0; fts_common_tables[i] != NULL; ++i) { - char* old_table_name; - dberr_t err = DB_SUCCESS; - fts_table.suffix = fts_common_tables[i]; - old_table_name = fts_get_table_name(&fts_table); + fts_get_table_name(&fts_table, old_table_name, true); err = fts_rename_one_aux_table(new_name, old_table_name, trx); - mem_free(old_table_name); - if (err != DB_SUCCESS) { return(err); } @@ -1617,12 +1615,8 @@ fts_rename_aux_tables( FTS_INIT_INDEX_TABLE(&fts_table, NULL, FTS_INDEX_TABLE, index); for (ulint j = 0; fts_index_selector[j].value; ++j) { - dberr_t err; - char* old_table_name; - fts_table.suffix = fts_get_suffix(j); - - old_table_name = fts_get_table_name(&fts_table); + fts_get_table_name(&fts_table, old_table_name, true); err = fts_rename_one_aux_table( new_name, old_table_name, trx); @@ -1631,8 +1625,6 @@ fts_rename_aux_tables( err = DB_DEADLOCK; fts_sql_rollback(trx);); - mem_free(old_table_name); - if (err != DB_SUCCESS) { return(err); } @@ -1660,11 +1652,11 @@ fts_drop_common_tables( for (i = 0; fts_common_tables[i] != NULL; ++i) { dberr_t err; - char* table_name; + char table_name[MAX_FULL_NAME_LEN]; fts_table->suffix = fts_common_tables[i]; - table_name = fts_get_table_name(fts_table); + fts_get_table_name(fts_table, table_name, true); err = fts_drop_table(trx, table_name); @@ -1672,8 +1664,6 @@ fts_drop_common_tables( if (err != DB_SUCCESS && err != DB_FAIL) { error = err; } - - mem_free(table_name); } return(error); @@ -1699,11 +1689,11 @@ fts_drop_index_split_tables( for (i = 0; fts_index_selector[i].value; ++i) { dberr_t err; - char* table_name; + char table_name[MAX_FULL_NAME_LEN]; fts_table.suffix = fts_get_suffix(i); - table_name = fts_get_table_name(&fts_table); + fts_get_table_name(&fts_table, table_name, true); err = fts_drop_table(trx, table_name); @@ -1711,8 +1701,6 @@ fts_drop_index_split_tables( if (err != DB_SUCCESS && err != DB_FAIL) { error = err; } - - mem_free(table_name); } return(error); @@ -1749,11 +1737,11 @@ fts_drop_index_tables( FTS_INIT_INDEX_TABLE(&fts_table, NULL, FTS_INDEX_TABLE, index); for (ulint i = 0; index_tables[i] != NULL; ++i) { - char* table_name; + char table_name[MAX_FULL_NAME_LEN]; fts_table.suffix = index_tables[i]; - table_name = fts_get_table_name(&fts_table); + fts_get_table_name(&fts_table, table_name, true); err = fts_drop_table(trx, table_name); @@ -1761,8 +1749,6 @@ fts_drop_index_tables( if (err != DB_SUCCESS && err != DB_FAIL) { error = err; } - - mem_free(table_name); } #endif /* FTS_DOC_STATS_DEBUG */ @@ -1832,26 +1818,6 @@ fts_drop_tables( } /*********************************************************************//** -Prepare the SQL, so that all '%s' are replaced by the common prefix. -@return sql string, use mem_free() to free the memory */ -static -char* -fts_prepare_sql( -/*============*/ - fts_table_t* fts_table, /*!< in: table name info */ - const char* my_template) /*!< in: sql template */ -{ - char* sql; - char* name_prefix; - - name_prefix = fts_get_table_name_prefix(fts_table); - sql = ut_strreplace(my_template, "%s", name_prefix); - mem_free(name_prefix); - - return(sql); -} - -/*********************************************************************//** Creates 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. @@ -1865,12 +1831,15 @@ fts_create_common_tables( const char* name, /*!< in: table name normalized.*/ bool skip_doc_id_index)/*!< in: Skip index on doc id */ { - char* sql; dberr_t error; que_t* graph; fts_table_t fts_table; mem_heap_t* heap = mem_heap_create(1024); pars_info_t* info; + char fts_name[MAX_FULL_NAME_LEN]; + char full_name[sizeof(fts_common_tables) / sizeof(char*)] + [MAX_FULL_NAME_LEN]; + ulint i; FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table); @@ -1882,9 +1851,19 @@ fts_create_common_tables( } /* Create the FTS tables that are common to an FTS index. */ - sql = fts_prepare_sql(&fts_table, fts_create_common_tables_sql); - graph = fts_parse_sql_no_dict_lock(NULL, NULL, sql); - mem_free(sql); + info = pars_info_create(); + + for (i = 0; fts_common_tables[i] != NULL; ++i) { + + fts_table.suffix = fts_common_tables[i]; + fts_get_table_name(&fts_table, full_name[i], true); + + pars_info_bind_id(info, true, + fts_common_tables[i], full_name[i]); + } + + graph = fts_parse_sql_no_dict_lock(NULL, info, + fts_create_common_tables_sql); error = fts_eval_sql(trx, graph); @@ -1896,9 +1875,14 @@ fts_create_common_tables( } /* Write the default settings to the config table. */ + info = pars_info_create(); + fts_table.suffix = "CONFIG"; + fts_get_table_name(&fts_table, fts_name, true); + pars_info_bind_id(info, true, "config_table", fts_name); + graph = fts_parse_sql_no_dict_lock( - &fts_table, NULL, fts_config_table_insert_values_sql); + &fts_table, info, fts_config_table_insert_values_sql); error = fts_eval_sql(trx, graph); @@ -1966,13 +1950,15 @@ fts_create_one_index_table( { dict_field_t* field; dict_table_t* new_table = NULL; - char* table_name = fts_get_table_name(fts_table); + char table_name[MAX_FULL_NAME_LEN]; dberr_t error; CHARSET_INFO* charset; ulint flags2 = 0; ut_ad(index->type & DICT_FTS); + fts_get_table_name(fts_table, table_name, true); + if (srv_file_per_table) { flags2 = DICT_TF2_USE_TABLESPACE; } @@ -2016,8 +2002,6 @@ fts_create_one_index_table( "Fail to create FTS index table %s", table_name); } - mem_free(table_name); - return(new_table); } @@ -2040,23 +2024,27 @@ fts_create_index_tables_low( que_t* graph; fts_table_t fts_table; dberr_t error = DB_SUCCESS; + pars_info_t* info; mem_heap_t* heap = mem_heap_create(1024); + char fts_name[MAX_FULL_NAME_LEN]; fts_table.type = FTS_INDEX_TABLE; fts_table.index_id = index->id; fts_table.table_id = table_id; - fts_table.parent = table_name; fts_table.table = index->table; #ifdef FTS_DOC_STATS_DEBUG - char* sql; - /* Create the FTS auxiliary tables that are specific to an FTS index. */ - sql = fts_prepare_sql(&fts_table, fts_create_index_tables_sql); + info = pars_info_create(); + + fts_table.suffix = "DOC_ID"; + fts_get_table_name(&fts_table, fts_name, true); - graph = fts_parse_sql_no_dict_lock(NULL, NULL, sql); - mem_free(sql); + pars_info_bind_id(info, true, "doc_id_table", fts_name); + + graph = fts_parse_sql_no_dict_lock(NULL, info, + fts_create_index_tables_sql); error = fts_eval_sql(trx, graph); que_graph_free(graph); @@ -2065,6 +2053,8 @@ fts_create_index_tables_low( for (i = 0; fts_index_selector[i].value && error == DB_SUCCESS; ++i) { dict_table_t* new_table; + info = pars_info_create(); + /* Create the FTS auxiliary tables that are specific to an FTS index. We need to preserve the table_id %s which fts_parse_sql_no_dict_lock() will fill in for us. */ @@ -2078,8 +2068,12 @@ fts_create_index_tables_low( break; } + fts_get_table_name(&fts_table, fts_name, true); + + pars_info_bind_id(info, true, "table", fts_name); + graph = fts_parse_sql_no_dict_lock( - &fts_table, NULL, fts_create_index_sql); + &fts_table, info, fts_create_index_sql); error = fts_eval_sql(trx, graph); que_graph_free(graph); @@ -2632,7 +2626,6 @@ 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, or NULL */ doc_id_t doc_id) /*!< in: DOC ID to set */ { table->fts->cache->synced_doc_id = doc_id; @@ -2641,7 +2634,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, trx); + table, table->fts->cache->synced_doc_id, trx); } @@ -2704,6 +2697,7 @@ fts_cmp_set_sync_doc_id( fts_table_t fts_table; que_t* graph = NULL; fts_cache_t* cache = table->fts->cache; + char table_name[MAX_FULL_NAME_LEN]; retry: ut_a(table->fts->doc_col != ULINT_UNDEFINED); @@ -2712,8 +2706,6 @@ retry: fts_table.type = FTS_COMMON_TABLE; fts_table.table = table; - fts_table.parent = table->name; - trx = trx_allocate_for_background(); trx->op_info = "update the next FTS document id"; @@ -2723,10 +2715,13 @@ retry: pars_info_bind_function( info, "my_func", fts_fetch_store_doc_id, doc_id); + fts_get_table_name(&fts_table, table_name); + pars_info_bind_id(info, true, "config_table", table_name); + graph = fts_parse_sql( &fts_table, info, "DECLARE FUNCTION my_func;\n" - "DECLARE CURSOR c IS SELECT value FROM \"%s\"" + "DECLARE CURSOR c IS SELECT value FROM $config_table" " WHERE key = 'synced_doc_id' FOR UPDATE;\n" "BEGIN\n" "" @@ -2770,7 +2765,7 @@ retry: if (doc_id_cmp > *doc_id) { error = fts_update_sync_doc_id( - table, table->name, cache->synced_doc_id, trx); + table, cache->synced_doc_id, trx); } *doc_id = cache->next_doc_id; @@ -2808,7 +2803,6 @@ 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 */ { @@ -2820,16 +2814,12 @@ fts_update_sync_doc_id( dberr_t error; ibool local_trx = FALSE; fts_cache_t* cache = table->fts->cache; + char fts_name[MAX_FULL_NAME_LEN]; fts_table.suffix = "CONFIG"; fts_table.table_id = table->id; fts_table.type = FTS_COMMON_TABLE; fts_table.table = table; - if (table_name) { - fts_table.parent = table_name; - } else { - fts_table.parent = table->name; - } if (!trx) { trx = trx_allocate_for_background(); @@ -2845,10 +2835,14 @@ fts_update_sync_doc_id( pars_info_bind_varchar_literal(info, "doc_id", id, id_len); + fts_get_table_name(&fts_table, fts_name, + table->fts->fts_status & TABLE_DICT_LOCKED); + pars_info_bind_id(info, true, "table_name", fts_name); + graph = fts_parse_sql( &fts_table, info, "BEGIN " - "UPDATE \"%s\" SET value = :doc_id" + "UPDATE $table_name SET value = :doc_id" " WHERE key = 'synced_doc_id';"); error = fts_eval_sql(trx, graph); @@ -2995,6 +2989,7 @@ fts_delete( /* Note the deleted document for OPTIMIZE to purge. */ if (error == DB_SUCCESS) { + char table_name[MAX_FULL_NAME_LEN]; trx->op_info = "adding doc id to FTS DELETED"; @@ -3002,10 +2997,13 @@ fts_delete( fts_table.suffix = "DELETED"; + fts_get_table_name(&fts_table, table_name); + pars_info_bind_id(info, true, "deleted", table_name); + graph = fts_parse_sql( &fts_table, info, - "BEGIN INSERT INTO \"%s\" VALUES (:doc_id);"); + "BEGIN INSERT INTO $deleted VALUES (:doc_id);"); error = fts_eval_sql(trx, graph); @@ -3824,11 +3822,15 @@ fts_write_node( ib_time_t start_time; doc_id_t last_doc_id; doc_id_t first_doc_id; + char table_name[MAX_FULL_NAME_LEN]; if (*graph) { info = (*graph)->info; } else { info = pars_info_create(); + + fts_get_table_name(fts_table, table_name); + pars_info_bind_id(info, true, "index_table_name", table_name); } pars_info_bind_varchar_literal(info, "token", word->f_str, word->f_len); @@ -3854,11 +3856,12 @@ fts_write_node( DATA_BLOB, DATA_BINARY_TYPE); if (!*graph) { + *graph = fts_parse_sql( fts_table, info, "BEGIN\n" - "INSERT INTO \"%s\" VALUES " + "INSERT INTO $index_table_name VALUES " "(:token, :first_doc_id," " :last_doc_id, :doc_count, :ilist);"); } @@ -3885,6 +3888,7 @@ fts_sync_add_deleted_cache( pars_info_t* info; que_t* graph; fts_table_t fts_table; + char table_name[MAX_FULL_NAME_LEN]; doc_id_t dummy = 0; dberr_t error = DB_SUCCESS; ulint n_elems = ib_vector_size(doc_ids); @@ -3900,10 +3904,13 @@ fts_sync_add_deleted_cache( FTS_INIT_FTS_TABLE( &fts_table, "DELETED_CACHE", FTS_COMMON_TABLE, sync->table); + fts_get_table_name(&fts_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); + graph = fts_parse_sql( &fts_table, info, - "BEGIN INSERT INTO \"%s\" VALUES (:doc_id);"); + "BEGIN INSERT INTO $table_name VALUES (:doc_id);"); for (i = 0; i < n_elems && error == DB_SUCCESS; ++i) { fts_update_t* update; @@ -4080,6 +4087,7 @@ fts_sync_write_doc_stat( doc_id_t doc_id; dberr_t error = DB_SUCCESS; ib_uint32_t word_count; + char table_name[MAX_FULL_NAME_LEN]; if (*graph) { info = (*graph)->info; @@ -4102,10 +4110,15 @@ fts_sync_write_doc_stat( FTS_INIT_INDEX_TABLE( &fts_table, "DOC_ID", FTS_INDEX_TABLE, index); + fts_get_table_name(&fts_table, table_name); + + pars_info_bind_id(info, true, "doc_id_table", table_name); + *graph = fts_parse_sql( &fts_table, info, - "BEGIN INSERT INTO \"%s\" VALUES (:doc_id, :count);"); + "BEGIN " + "INSERT INTO $doc_id_table VALUES (:doc_id, :count);"); } for (;;) { @@ -4227,6 +4240,7 @@ fts_is_word_in_index( { pars_info_t* info; dberr_t error; + char table_name[MAX_FULL_NAME_LEN]; trx->op_info = "looking up word in FTS index"; @@ -4236,6 +4250,8 @@ fts_is_word_in_index( info = pars_info_create(); } + fts_get_table_name(fts_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); pars_info_bind_function(info, "my_func", fts_lookup_word, found); pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len); @@ -4246,7 +4262,7 @@ fts_is_word_in_index( "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" " SELECT doc_count\n" - " FROM \"%s\"\n" + " FROM $table_name\n" " WHERE word = :word " " ORDER BY first_doc_id;\n" "BEGIN\n" @@ -4995,6 +5011,7 @@ fts_get_rows_count( que_t* graph; dberr_t error; ulint count = 0; + char table_name[MAX_FULL_NAME_LEN]; trx = trx_allocate_for_background(); @@ -5004,13 +5021,16 @@ fts_get_rows_count( pars_info_bind_function(info, "my_func", fts_read_ulint, &count); + fts_get_table_name(fts_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); + graph = fts_parse_sql( fts_table, info, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" " SELECT COUNT(*) " - " FROM \"%s\";\n" + " FROM $table_name;\n" "BEGIN\n" "\n" "OPEN c;\n" @@ -6219,7 +6239,7 @@ fts_rename_one_aux_table_to_hex_format( { const char* ptr; fts_table_t fts_table; - char* new_name; + char new_name[MAX_FULL_NAME_LEN]; dberr_t error; ptr = strchr(aux_table->name, '/'); @@ -6260,12 +6280,11 @@ fts_rename_one_aux_table_to_hex_format( ut_a(fts_table.suffix != NULL); - fts_table.parent = parent_table->name; fts_table.table_id = aux_table->parent_id; fts_table.index_id = aux_table->index_id; fts_table.table = parent_table; - new_name = fts_get_table_name(&fts_table); + fts_get_table_name(&fts_table, new_name); ut_ad(strcmp(new_name, aux_table->name) != 0); if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { @@ -6286,8 +6305,6 @@ fts_rename_one_aux_table_to_hex_format( aux_table->name, new_name); } - mem_free(new_name); - return (error); } diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index 28e704eb9a5..0d5185cc5fb 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -43,6 +43,9 @@ Completed 2011/7/10 Sunny and Jimmy Yang /** The FTS optimize thread's work queue. */ static ib_wqueue_t* fts_optimize_wq; +/** The FTS vector to store fts_slot_t */ +static ib_vector_t* fts_slots; + /** Time to wait for a message. */ static const ulint FTS_QUEUE_WAIT_IN_USECS = 5000000; @@ -58,15 +61,6 @@ static const ulint FTS_WORD_NODES_INIT_SIZE = 64; /** Last time we did check whether system need a sync */ static ib_time_t last_check_sync_time; -/** State of a table within the optimization sub system. */ -enum fts_state_t { - FTS_STATE_LOADED, - FTS_STATE_RUNNING, - FTS_STATE_SUSPENDED, - FTS_STATE_DONE, - FTS_STATE_EMPTY -}; - /** FTS optimize thread message types. */ enum fts_msg_type_t { FTS_MSG_STOP, /*!< Stop optimizing and exit thread */ @@ -175,11 +169,11 @@ struct fts_encode_t { /** We use this information to determine when to start the optimize cycle for a table. */ struct fts_slot_t { - dict_table_t* table; /*!< Table to optimize */ + /** table identifier, or 0 if the slot is empty */ + table_id_t table_id; - table_id_t table_id; /*!< Table id */ - - fts_state_t state; /*!< State of this slot */ + /** whether this slot is being processed */ + bool running; ulint added; /*!< Number of doc ids added since the last time this table was optimized */ @@ -232,27 +226,30 @@ static ulint FTS_ZIP_BLOCK_SIZE = 1024; /** The amount of time optimizing in a single pass, in milliseconds. */ static ib_time_t fts_optimize_time_limit = 0; +/** It's defined in fts0fts.cc */ +extern const char* fts_common_tables[]; + /** SQL Statement for changing state of rows to be deleted from FTS Index. */ static const char* fts_init_delete_sql = "BEGIN\n" "\n" - "INSERT INTO \"%s_BEING_DELETED\"\n" - "SELECT doc_id FROM \"%s_DELETED\";\n" + "INSERT INTO $BEING_DELETED\n" + "SELECT doc_id FROM $DELETED;\n" "\n" - "INSERT INTO \"%s_BEING_DELETED_CACHE\"\n" - "SELECT doc_id FROM \"%s_DELETED_CACHE\";\n"; + "INSERT INTO $BEING_DELETED_CACHE\n" + "SELECT doc_id FROM $DELETED_CACHE;\n"; static const char* fts_delete_doc_ids_sql = "BEGIN\n" "\n" - "DELETE FROM \"%s_DELETED\" WHERE doc_id = :doc_id1;\n" - "DELETE FROM \"%s_DELETED_CACHE\" WHERE doc_id = :doc_id2;\n"; + "DELETE FROM $DELETED WHERE doc_id = :doc_id1;\n" + "DELETE FROM $DELETED_CACHE WHERE doc_id = :doc_id2;\n"; static const char* fts_end_delete_sql = "BEGIN\n" "\n" - "DELETE FROM \"%s_BEING_DELETED\";\n" - "DELETE FROM \"%s_BEING_DELETED_CACHE\";\n"; + "DELETE FROM $BEING_DELETED;\n" + "DELETE FROM $BEING_DELETED_CACHE;\n"; /**********************************************************************//** Initialize fts_zip_t. */ @@ -483,21 +480,17 @@ fts_index_fetch_nodes( { pars_info_t* info; dberr_t error; + char table_name[MAX_FULL_NAME_LEN]; trx->op_info = "fetching FTS index nodes"; if (*graph) { info = (*graph)->info; } else { - info = pars_info_create(); - } - - pars_info_bind_function(info, "my_func", fetch->read_record, fetch); - pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len); - - if (!*graph) { ulint selected; + info = pars_info_create(); + ut_a(fts_table->type == FTS_INDEX_TABLE); selected = fts_select_index(fts_table->charset, @@ -505,6 +498,16 @@ fts_index_fetch_nodes( fts_table->suffix = fts_get_suffix(selected); + fts_get_table_name(fts_table, table_name); + + pars_info_bind_id(info, true, "table_name", table_name); + } + + pars_info_bind_function(info, "my_func", fetch->read_record, fetch); + pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len); + + if (!*graph) { + *graph = fts_parse_sql( fts_table, info, @@ -512,7 +515,7 @@ fts_index_fetch_nodes( "DECLARE CURSOR c IS" " SELECT word, doc_count, first_doc_id, last_doc_id, " "ilist\n" - " FROM \"%s\"\n" + " FROM $table_name\n" " WHERE word LIKE :word\n" " ORDER BY first_doc_id;\n" "BEGIN\n" @@ -812,6 +815,8 @@ fts_index_fetch_words( fts_index_selector[selected].value; selected++) { + char table_name[MAX_FULL_NAME_LEN]; + optim->fts_index_table.suffix = fts_get_suffix(selected); /* We've search all indexes. */ @@ -827,13 +832,16 @@ fts_index_fetch_words( pars_info_bind_varchar_literal( info, "word", word->f_str, word->f_len); + fts_get_table_name(&optim->fts_index_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); + graph = fts_parse_sql( &optim->fts_index_table, info, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" " SELECT word\n" - " FROM \"%s\"\n" + " FROM $table_name\n" " WHERE word > :word\n" " ORDER BY word;\n" "BEGIN\n" @@ -975,6 +983,7 @@ fts_table_fetch_doc_ids( que_t* graph; pars_info_t* info = pars_info_create(); ibool alloc_bk_trx = FALSE; + char table_name[MAX_FULL_NAME_LEN]; ut_a(fts_table->suffix != NULL); ut_a(fts_table->type == FTS_COMMON_TABLE); @@ -988,12 +997,15 @@ fts_table_fetch_doc_ids( pars_info_bind_function(info, "my_func", fts_fetch_doc_ids, doc_ids); + fts_get_table_name(fts_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); + graph = fts_parse_sql( fts_table, info, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" - " SELECT doc_id FROM \"%s\";\n" + " SELECT doc_id FROM $table_name;\n" "BEGIN\n" "\n" "OPEN c;\n" @@ -1446,7 +1458,7 @@ fts_optimize_write_word( que_t* graph; ulint selected; dberr_t error = DB_SUCCESS; - char* table_name = fts_get_table_name(fts_table); + char table_name[MAX_FULL_NAME_LEN]; info = pars_info_create(); @@ -1464,11 +1476,13 @@ fts_optimize_write_word( word->f_str, word->f_len); fts_table->suffix = fts_get_suffix(selected); + fts_get_table_name(fts_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); graph = fts_parse_sql( fts_table, info, - "BEGIN DELETE FROM \"%s\" WHERE word = :word;"); + "BEGIN DELETE FROM $table_name WHERE word = :word;"); error = fts_eval_sql(trx, graph); @@ -1482,8 +1496,6 @@ fts_optimize_write_word( fts_que_graph_free(graph); graph = NULL; - mem_free(table_name); - /* Even if the operation needs to be rolled back and redone, we iterate over the nodes in order to free the ilist. */ for (i = 0; i < ib_vector_size(nodes); ++i) { @@ -1609,12 +1621,10 @@ fts_optimize_create( optim->trx = trx_allocate_for_background(); - optim->fts_common_table.parent = table->name; optim->fts_common_table.table_id = table->id; optim->fts_common_table.type = FTS_COMMON_TABLE; optim->fts_common_table.table = table; - optim->fts_index_table.parent = table->name; optim->fts_index_table.table_id = table->id; optim->fts_index_table.type = FTS_INDEX_TABLE; optim->fts_index_table.table = table; @@ -1735,7 +1745,7 @@ fts_optimize_free( fts_doc_ids_free(optim->to_delete); fts_optimize_graph_free(&optim->graph); - mem_free(optim->name_prefix); + ut_free(optim->name_prefix); /* This will free the heap from which optim itself was allocated. */ mem_heap_free(heap); @@ -2075,9 +2085,10 @@ fts_optimize_purge_deleted_doc_ids( pars_info_t* info; que_t* graph; fts_update_t* update; - char* sql_str; doc_id_t write_doc_id; dberr_t error = DB_SUCCESS; + char deleted[MAX_FULL_NAME_LEN]; + char deleted_cache[MAX_FULL_NAME_LEN]; info = pars_info_create(); @@ -2094,14 +2105,17 @@ fts_optimize_purge_deleted_doc_ids( fts_bind_doc_id(info, "doc_id1", &write_doc_id); fts_bind_doc_id(info, "doc_id2", &write_doc_id); - /* Since we only replace the table_id and don't construct the full - name, we do substitution ourselves. Remember to free sql_str. */ - sql_str = ut_strreplace( - fts_delete_doc_ids_sql, "%s", optim->name_prefix); + /* Make sure the following two names are consistent with the name + used in the fts_delete_doc_ids_sql */ + optim->fts_common_table.suffix = fts_common_tables[3]; + fts_get_table_name(&optim->fts_common_table, deleted); + pars_info_bind_id(info, true, fts_common_tables[3], deleted); - graph = fts_parse_sql(NULL, info, sql_str); + optim->fts_common_table.suffix = fts_common_tables[4]; + fts_get_table_name(&optim->fts_common_table, deleted_cache); + pars_info_bind_id(info, true, fts_common_tables[4], deleted_cache); - mem_free(sql_str); + graph = fts_parse_sql(NULL, info, fts_delete_doc_ids_sql); /* Delete the doc ids that were copied at the start. */ for (i = 0; i < ib_vector_size(optim->to_delete->doc_ids); ++i) { @@ -2142,17 +2156,26 @@ fts_optimize_purge_deleted_doc_id_snapshot( { dberr_t error; que_t* graph; - char* sql_str; + pars_info_t* info; + char being_deleted[MAX_FULL_NAME_LEN]; + char being_deleted_cache[MAX_FULL_NAME_LEN]; + + info = pars_info_create(); + + /* Make sure the following two names are consistent with the name + used in the fts_end_delete_sql */ + optim->fts_common_table.suffix = fts_common_tables[0]; + fts_get_table_name(&optim->fts_common_table, being_deleted); + pars_info_bind_id(info, true, fts_common_tables[0], being_deleted); - /* Since we only replace the table_id and don't construct - the full name, we do the '%s' substitution ourselves. */ - sql_str = ut_strreplace(fts_end_delete_sql, "%s", optim->name_prefix); + optim->fts_common_table.suffix = fts_common_tables[1]; + fts_get_table_name(&optim->fts_common_table, being_deleted_cache); + pars_info_bind_id(info, true, fts_common_tables[1], + being_deleted_cache); /* Delete the doc ids that were copied to delete pending state at the start of optimize. */ - graph = fts_parse_sql(NULL, NULL, sql_str); - - mem_free(sql_str); + graph = fts_parse_sql(NULL, info, fts_end_delete_sql); error = fts_eval_sql(optim->trx, graph); fts_que_graph_free(graph); @@ -2192,16 +2215,35 @@ fts_optimize_create_deleted_doc_id_snapshot( { dberr_t error; que_t* graph; - char* sql_str; + pars_info_t* info; + char being_deleted[MAX_FULL_NAME_LEN]; + char deleted[MAX_FULL_NAME_LEN]; + char being_deleted_cache[MAX_FULL_NAME_LEN]; + char deleted_cache[MAX_FULL_NAME_LEN]; + + info = pars_info_create(); - /* Since we only replace the table_id and don't construct the - full name, we do the substitution ourselves. */ - sql_str = ut_strreplace(fts_init_delete_sql, "%s", optim->name_prefix); + /* Make sure the following four names are consistent with the name + used in the fts_init_delete_sql */ + optim->fts_common_table.suffix = fts_common_tables[0]; + fts_get_table_name(&optim->fts_common_table, being_deleted); + pars_info_bind_id(info, true, fts_common_tables[0], being_deleted); - /* Move doc_ids that are to be deleted to state being deleted. */ - graph = fts_parse_sql(NULL, NULL, sql_str); + optim->fts_common_table.suffix = fts_common_tables[3]; + fts_get_table_name(&optim->fts_common_table, deleted); + pars_info_bind_id(info, true, fts_common_tables[3], deleted); + + optim->fts_common_table.suffix = fts_common_tables[1]; + fts_get_table_name(&optim->fts_common_table, being_deleted_cache); + pars_info_bind_id(info, true, fts_common_tables[1], + being_deleted_cache); - mem_free(sql_str); + optim->fts_common_table.suffix = fts_common_tables[4]; + fts_get_table_name(&optim->fts_common_table, deleted_cache); + pars_info_bind_id(info, true, fts_common_tables[4], deleted_cache); + + /* Move doc_ids that are to be deleted to state being deleted. */ + graph = fts_parse_sql(NULL, info, fts_init_delete_sql); error = fts_eval_sql(optim->trx, graph); @@ -2404,31 +2446,35 @@ fts_optimize_table_bk( fts_slot_t* slot) /*!< in: table to optimiza */ { dberr_t error; - dict_table_t* table = slot->table; - fts_t* fts = table->fts; /* Avoid optimizing tables that were optimized recently. */ if (slot->last_run > 0 && (ut_time() - slot->last_run) < slot->interval_time) { return(DB_SUCCESS); + } - } else if (fts && fts->cache - && fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) { + dict_table_t* table = dict_table_open_on_id( + slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); + if (table && fil_table_accessible(table) + && table->fts && table->fts->cache + && table->fts->cache->deleted >= FTS_OPTIMIZE_THRESHOLD) { error = fts_optimize_table(table); + slot->last_run = ut_time(); + if (error == DB_SUCCESS) { - slot->state = FTS_STATE_DONE; - slot->last_run = 0; - slot->completed = ut_time(); + slot->running = false; + slot->completed = slot->last_run; } } else { + /* Note time this run completed. */ + slot->last_run = ut_time(); error = DB_SUCCESS; } - /* Note time this run completed. */ - slot->last_run = ut_time(); + dict_table_close(table, FALSE, FALSE); return(error); } @@ -2647,85 +2693,60 @@ fts_optimize_request_sync_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap); } -/**********************************************************************//** -Add the table to the vector if it doesn't already exist. */ -static -ibool -fts_optimize_new_table( -/*===================*/ - ib_vector_t* tables, /*!< in/out: vector of tables */ - dict_table_t* table) /*!< in: table to add */ +/** Add a table to fts_slots if it doesn't already exist. */ +static bool fts_optimize_new_table(dict_table_t* table) { ulint i; fts_slot_t* slot; - ulint empty_slot = ULINT_UNDEFINED; + fts_slot_t* empty = NULL; + const table_id_t table_id = table->id; + ut_ad(table_id); /* Search for duplicates, also find a free slot if one exists. */ - for (i = 0; i < ib_vector_size(tables); ++i) { + for (i = 0; i < ib_vector_size(fts_slots); ++i) { - slot = static_cast<fts_slot_t*>( - ib_vector_get(tables, i)); + slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i)); - if (slot->state == FTS_STATE_EMPTY) { - empty_slot = i; - } else if (slot->table->id == table->id) { + if (!slot->table_id) { + empty = slot; + } else if (slot->table_id == table_id) { /* Already exists in our optimize queue. */ - ut_ad(slot->table_id = table->id); return(FALSE); } } - /* Reuse old slot. */ - if (empty_slot != ULINT_UNDEFINED) { - - slot = static_cast<fts_slot_t*>( - ib_vector_get(tables, empty_slot)); - - ut_a(slot->state == FTS_STATE_EMPTY); - - } else { /* Create a new slot. */ - - slot = static_cast<fts_slot_t*>(ib_vector_push(tables, NULL)); - } + slot = empty ? empty : static_cast<fts_slot_t*>( + ib_vector_push(fts_slots, NULL)); memset(slot, 0x0, sizeof(*slot)); - slot->table = table; slot->table_id = table->id; - slot->state = FTS_STATE_LOADED; + slot->running = false; slot->interval_time = FTS_OPTIMIZE_INTERVAL_IN_SECS; return(TRUE); } -/**********************************************************************//** -Remove the table from the vector if it exists. */ -static -ibool -fts_optimize_del_table( -/*===================*/ - ib_vector_t* tables, /*!< in/out: vector of tables */ - fts_msg_del_t* msg) /*!< in: table to delete */ +/** Remove a table from fts_slots if it exists. +@param[in,out] table table to be removed from fts_slots */ +static bool fts_optimize_del_table(const dict_table_t* table) { - ulint i; - dict_table_t* table = msg->table; + const table_id_t table_id = table->id; + ut_ad(table_id); - for (i = 0; i < ib_vector_size(tables); ++i) { + for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { fts_slot_t* slot; - slot = static_cast<fts_slot_t*>(ib_vector_get(tables, i)); + slot = static_cast<fts_slot_t*>(ib_vector_get(fts_slots, i)); - /* FIXME: Should we assert on this ? */ - if (slot->state != FTS_STATE_EMPTY - && slot->table->id == table->id) { - - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: FTS Optimize Removing " - "table %s\n", table->name); - - slot->table = NULL; - slot->state = FTS_STATE_EMPTY; + if (slot->table_id == table_id) { + if (fts_enable_diag_print) { + ib_logf(IB_LOG_LEVEL_INFO, + "FTS Optimize Removing table %s", + table->name); + } + slot->table_id = 0; return(TRUE); } } @@ -2734,14 +2755,9 @@ fts_optimize_del_table( } /**********************************************************************//** -Calculate how many of the registered tables need to be optimized. +Calculate how many tables in fts_slots need to be optimized. @return no. of tables to optimize */ -static -ulint -fts_optimize_how_many( -/*==================*/ - const ib_vector_t* tables) /*!< in: registered tables - vector*/ +static ulint fts_optimize_how_many() { ulint i; ib_time_t delta; @@ -2750,15 +2766,14 @@ fts_optimize_how_many( current_time = ut_time(); - for (i = 0; i < ib_vector_size(tables); ++i) { - const fts_slot_t* slot; - - slot = static_cast<const fts_slot_t*>( - ib_vector_get_const(tables, i)); + for (i = 0; i < ib_vector_size(fts_slots); ++i) { + const fts_slot_t* slot = static_cast<const fts_slot_t*>( + ib_vector_get_const(fts_slots, i)); + if (slot->table_id == 0) { + continue; + } - switch (slot->state) { - case FTS_STATE_DONE: - case FTS_STATE_LOADED: + if (!slot->running) { ut_a(slot->completed <= current_time); delta = current_time - slot->completed; @@ -2767,9 +2782,7 @@ fts_optimize_how_many( if (delta >= slot->interval_time) { ++n_tables; } - break; - - case FTS_STATE_RUNNING: + } else { ut_a(slot->last_run <= current_time); delta = current_time - slot->last_run; @@ -2777,15 +2790,7 @@ fts_optimize_how_many( if (delta > slot->interval_time) { ++n_tables; } - break; - - /* Slots in a state other than the above - are ignored. */ - case FTS_STATE_EMPTY: - case FTS_STATE_SUSPENDED: - break; } - } return(n_tables); @@ -2794,12 +2799,7 @@ fts_optimize_how_many( /**********************************************************************//** Check if the total memory used by all FTS table exceeds the maximum limit. @return true if a sync is needed, false otherwise */ -static -bool -fts_is_sync_needed( -/*===============*/ - const ib_vector_t* tables) /*!< in: registered tables - vector*/ +static bool fts_is_sync_needed() { ulint total_memory = 0; double time_diff = difftime(ut_time(), last_check_sync_time); @@ -2810,17 +2810,26 @@ fts_is_sync_needed( last_check_sync_time = ut_time(); - for (ulint i = 0; i < ib_vector_size(tables); ++i) { - const fts_slot_t* slot; + for (ulint i = 0; i < ib_vector_size(fts_slots); ++i) { + const fts_slot_t* slot = static_cast<const fts_slot_t*>( + ib_vector_get_const(fts_slots, i)); + + if (slot->table_id == 0) { + continue; + } - slot = static_cast<const fts_slot_t*>( - ib_vector_get_const(tables, i)); + dict_table_t* table = dict_table_open_on_id( + slot->table_id, FALSE, DICT_TABLE_OP_NORMAL); + if (!table) { + continue; + } - if (slot->state != FTS_STATE_EMPTY && slot->table - && slot->table->fts) { - total_memory += slot->table->fts->cache->total_size; + if (table->fts && table->fts->cache) { + total_memory += table->fts->cache->total_size; } + dict_table_close(table, FALSE, FALSE); + if (total_memory > fts_max_total_cache_size) { return(true); } @@ -2831,16 +2840,12 @@ fts_is_sync_needed( /** Sync fts cache of a table @param[in] table_id table id */ -void -fts_optimize_sync_table( - table_id_t table_id) +static void fts_optimize_sync_table(table_id_t table_id) { - dict_table_t* table = NULL; - - table = dict_table_open_on_id(table_id, FALSE, DICT_TABLE_OP_NORMAL); - - if (table) { - if (dict_table_has_fts_index(table) && table->fts->cache) { + if (dict_table_t* table = dict_table_open_on_id( + table_id, FALSE, DICT_TABLE_OP_NORMAL)) { + if (fil_table_accessible(table) + && table->fts && table->fts->cache) { fts_sync_table(table, true, false, false); } @@ -2858,7 +2863,6 @@ fts_optimize_thread( void* arg) /*!< in: work queue*/ { mem_heap_t* heap; - ib_vector_t* tables; ib_alloc_t* heap_alloc; ulint current = 0; ibool done = FALSE; @@ -2873,7 +2877,7 @@ fts_optimize_thread( heap = mem_heap_create(sizeof(dict_table_t*) * 64); heap_alloc = ib_heap_allocator_create(heap); - tables = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4); + fts_slots = ib_vector_create(heap_alloc, sizeof(fts_slot_t), 4); while(!done && srv_shutdown_state == SRV_SHUTDOWN_NONE) { @@ -2884,28 +2888,18 @@ fts_optimize_thread( && ib_wqueue_is_empty(wq) && n_tables > 0 && n_optimize > 0) { - - fts_slot_t* slot; - - ut_a(ib_vector_size(tables) > 0); - - slot = static_cast<fts_slot_t*>( - ib_vector_get(tables, current)); + fts_slot_t* slot = static_cast<fts_slot_t*>( + ib_vector_get(fts_slots, current)); /* Handle the case of empty slots. */ - if (slot->state != FTS_STATE_EMPTY) { - - slot->state = FTS_STATE_RUNNING; - + if (slot->table_id) { + slot->running = true; fts_optimize_table_bk(slot); } - ++current; - /* Wrap around the counter. */ - if (current >= ib_vector_size(tables)) { - n_optimize = fts_optimize_how_many(tables); - + if (++current >= ib_vector_size(fts_slots)) { + n_optimize = fts_optimize_how_many(); current = 0; } @@ -2917,7 +2911,7 @@ fts_optimize_thread( /* Timeout ? */ if (msg == NULL) { - if (fts_is_sync_needed(tables)) { + if (fts_is_sync_needed()) { fts_need_sync = true; } @@ -2933,17 +2927,16 @@ fts_optimize_thread( case FTS_MSG_ADD_TABLE: ut_a(!done); if (fts_optimize_new_table( - tables, - static_cast<dict_table_t*>( - msg->ptr))) { + static_cast<dict_table_t*>( + msg->ptr))) { ++n_tables; } break; case FTS_MSG_DEL_TABLE: if (fts_optimize_del_table( - tables, static_cast<fts_msg_del_t*>( - msg->ptr))) { + static_cast<fts_msg_del_t*>( + msg->ptr)->table)) { --n_tables; } @@ -2967,33 +2960,25 @@ fts_optimize_thread( } mem_heap_free(msg->heap); - - if (!done) { - n_optimize = fts_optimize_how_many(tables); - } else { - n_optimize = 0; - } + n_optimize = done ? 0 : fts_optimize_how_many(); } } /* Server is being shutdown, sync the data from FTS cache to disk if needed */ if (n_tables > 0) { - ulint i; - - for (i = 0; i < ib_vector_size(tables); i++) { - fts_slot_t* slot; - - slot = static_cast<fts_slot_t*>( - ib_vector_get(tables, i)); + for (ulint i = 0; i < ib_vector_size(fts_slots); i++) { + fts_slot_t* slot = static_cast<fts_slot_t*>( + ib_vector_get(fts_slots, i)); - if (slot->state != FTS_STATE_EMPTY) { - fts_optimize_sync_table(slot->table_id); + if (table_id_t table_id = slot->table_id) { + fts_optimize_sync_table(table_id); } } } - ib_vector_free(tables); + ib_vector_free(fts_slots); + fts_slots = NULL; ib_logf(IB_LOG_LEVEL_INFO, "FTS optimize thread exiting."); diff --git a/storage/xtradb/fts/fts0que.cc b/storage/xtradb/fts/fts0que.cc index b9ad43c626a..3419a1bd7ab 100644 --- a/storage/xtradb/fts/fts0que.cc +++ b/storage/xtradb/fts/fts0que.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. 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 @@ -2052,13 +2052,22 @@ fts_query_find_term( fts_select_t select; doc_id_t match_doc_id; trx_t* trx = query->trx; + char table_name[MAX_FULL_NAME_LEN]; trx->op_info = "fetching FTS index matching nodes"; if (*graph) { info = (*graph)->info; } else { + ulint selected; + info = pars_info_create(); + + selected = fts_select_index(*word->f_str); + query->fts_index_table.suffix = fts_get_suffix(selected); + + fts_get_table_name(&query->fts_index_table, table_name); + pars_info_bind_id(info, true, "index_table_name", table_name); } select.found = FALSE; @@ -2077,11 +2086,6 @@ fts_query_find_term( fts_bind_doc_id(info, "max_doc_id", &match_doc_id); if (!*graph) { - ulint selected; - - selected = fts_select_index(*word->f_str); - - query->fts_index_table.suffix = fts_get_suffix(selected); *graph = fts_parse_sql( &query->fts_index_table, @@ -2089,7 +2093,7 @@ fts_query_find_term( "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" " SELECT doc_count, ilist\n" - " FROM \"%s\"\n" + " FROM $index_table_name\n" " WHERE word LIKE :word AND " " first_doc_id <= :min_doc_id AND " " last_doc_id >= :max_doc_id\n" @@ -2188,6 +2192,7 @@ fts_query_total_docs_containing_term( que_t* graph; ulint selected; trx_t* trx = query->trx; + char table_name[MAX_FULL_NAME_LEN] trx->op_info = "fetching FTS index document count"; @@ -2202,13 +2207,17 @@ fts_query_total_docs_containing_term( query->fts_index_table.suffix = fts_get_suffix(selected); + fts_get_table_name(&query->fts_index_table, table_name); + + pars_info_bind_id(info, true, "index_table_name", table_name); + graph = fts_parse_sql( &query->fts_index_table, info, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" " SELECT doc_count\n" - " FROM %s\n" + " FROM $index_table_name\n" " WHERE word = :word " " ORDER BY first_doc_id;\n" "BEGIN\n" @@ -2267,6 +2276,7 @@ fts_query_terms_in_document( que_t* graph; doc_id_t read_doc_id; trx_t* trx = query->trx; + char table_name[MAX_FULL_NAME_LEN]; trx->op_info = "fetching FTS document term count"; @@ -2282,13 +2292,17 @@ fts_query_terms_in_document( query->fts_index_table.suffix = "DOC_ID"; + fts_get_table_name(&query->fts_index_table, table_name); + + pars_info_bind_id(info, true, "index_table_name", table_name); + graph = fts_parse_sql( &query->fts_index_table, info, "DECLARE FUNCTION my_func;\n" "DECLARE CURSOR c IS" " SELECT count\n" - " FROM \"%s\"\n" + " FROM $index_table_name\n" " WHERE doc_id = :doc_id " "BEGIN\n" "\n" @@ -3891,7 +3905,6 @@ fts_query( query.fts_common_table.type = FTS_COMMON_TABLE; query.fts_common_table.table_id = index->table->id; - query.fts_common_table.parent = index->table->name; query.fts_common_table.table = index->table; charset = fts_index_get_charset(index); @@ -3899,7 +3912,6 @@ fts_query( query.fts_index_table.type = FTS_INDEX_TABLE; query.fts_index_table.index_id = index->id; query.fts_index_table.table_id = index->table->id; - query.fts_index_table.parent = index->table->name; query.fts_index_table.charset = charset; query.fts_index_table.table = index->table; diff --git a/storage/xtradb/fts/fts0sql.cc b/storage/xtradb/fts/fts0sql.cc index cb8eff3cacc..cce21957f1b 100644 --- a/storage/xtradb/fts/fts0sql.cc +++ b/storage/xtradb/fts/fts0sql.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. 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 @@ -35,8 +36,7 @@ Created 2007-03-27 Sunny Bains #include "fts0vlc.ic" #endif -/** SQL statements for creating the ancillary FTS tables. %s must be replaced -with the indexed table's id. */ +/** SQL statements for creating the ancillary FTS tables. */ /** Preamble to all SQL statements. */ static const char* fts_sql_begin= @@ -95,76 +95,56 @@ fts_get_table_id( return(len); } -/******************************************************************//** -Construct the prefix name of an FTS table. -@return own: table name, must be freed with mem_free() */ -UNIV_INTERN -char* -fts_get_table_name_prefix( -/*======================*/ - const fts_table_t* - fts_table) /*!< in: Auxiliary table type */ +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[in] dict_locked whether dict_sys->mutex is being held +@return the prefix, must be freed with ut_free() */ +UNIV_INTERN char* fts_get_table_name_prefix(const fts_table_t* fts_table) { - int len; - const char* slash; - char* prefix_name; - int dbname_len = 0; - int prefix_name_len; char table_id[FTS_AUX_MIN_TABLE_ID_LENGTH]; - - slash = static_cast<const char*>( - memchr(fts_table->parent, '/', strlen(fts_table->parent))); - - if (slash) { - /* Print up to and including the separator. */ - dbname_len = static_cast<int>(slash - fts_table->parent) + 1; - } - - len = fts_get_table_id(fts_table, table_id); - - prefix_name_len = dbname_len + 4 + len + 1; - - prefix_name = static_cast<char*>(mem_alloc(prefix_name_len)); - - len = sprintf(prefix_name, "%.*sFTS_%s", - dbname_len, fts_table->parent, table_id); - - ut_a(len > 0); - ut_a(len == prefix_name_len - 1); - - return(prefix_name); + const size_t table_id_len = size_t(fts_get_table_id(fts_table, + table_id)) + 1; + mutex_enter(&dict_sys->mutex); + const char* slash = strchr(fts_table->table->name, '/'); + ut_ad(slash); + /* Include the separator as well. */ + const size_t dbname_len = (slash - fts_table->table->name) + 1; + ut_ad(dbname_len > 1); + const size_t prefix_name_len = dbname_len + 4 + table_id_len; + char* prefix_name = static_cast<char*>(ut_malloc(prefix_name_len)); + memcpy(prefix_name, fts_table->table->name, dbname_len); + mutex_exit(&dict_sys->mutex); + memcpy(prefix_name + dbname_len, "FTS_", 4); + memcpy(prefix_name + dbname_len + 4, table_id, table_id_len); + return prefix_name; } -/******************************************************************//** -Construct the name of an ancillary FTS table. -@return own: table name, must be freed with mem_free() */ +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[out] table_name a name up to MAX_FULL_NAME_LEN +@param[in] dict_locked whether dict_sys->mutex is being held */ UNIV_INTERN -char* -fts_get_table_name( -/*===============*/ - const fts_table_t* fts_table) - /*!< in: Auxiliary table type */ +void fts_get_table_name(const fts_table_t* fts_table, char* table_name, + bool dict_locked) { - int len; - char* name; - int name_len; - char* prefix_name; - - prefix_name = fts_get_table_name_prefix(fts_table); - - name_len = static_cast<int>( - strlen(prefix_name) + 1 + strlen(fts_table->suffix) + 1); - - name = static_cast<char*>(mem_alloc(name_len)); - - len = sprintf(name, "%s_%s", prefix_name, fts_table->suffix); - - ut_a(len > 0); - ut_a(len == name_len - 1); - - mem_free(prefix_name); - - return(name); + if (!dict_locked) { + mutex_enter(&dict_sys->mutex); + } + ut_ad(mutex_own(&dict_sys->mutex)); + const char* slash = strchr(fts_table->table->name, '/'); + ut_ad(slash); + /* Include the separator as well. */ + const size_t dbname_len = (slash - fts_table->table->name) + 1; + ut_ad(dbname_len > 1); + memcpy(table_name, fts_table->table->name, dbname_len); + if (!dict_locked) { + mutex_exit(&dict_sys->mutex); + } + memcpy(table_name += dbname_len, "FTS_", 4); + table_name += 4; + table_name += fts_get_table_id(fts_table, table_name); + *table_name++ = '_'; + strcpy(table_name, fts_table->suffix); } /******************************************************************//** @@ -180,24 +160,9 @@ fts_parse_sql( { char* str; que_t* graph; - char* str_tmp; ibool dict_locked; - if (fts_table != NULL) { - char* table_name; - - table_name = fts_get_table_name(fts_table); - str_tmp = ut_strreplace(sql, "%s", table_name); - mem_free(table_name); - } else { - ulint sql_len = strlen(sql) + 1; - - str_tmp = static_cast<char*>(mem_alloc(sql_len)); - strcpy(str_tmp, sql); - } - - str = ut_str3cat(fts_sql_begin, str_tmp, fts_sql_end); - mem_free(str_tmp); + str = ut_str3cat(fts_sql_begin, sql, fts_sql_end); dict_locked = (fts_table && fts_table->table->fts && (fts_table->table->fts->fts_status @@ -223,7 +188,7 @@ fts_parse_sql( } /******************************************************************//** -Parse an SQL string. %s is replaced with the table's id. +Parse an SQL string. @return query graph */ UNIV_INTERN que_t* @@ -235,28 +200,10 @@ fts_parse_sql_no_dict_lock( { char* str; que_t* graph; - char* str_tmp = NULL; -#ifdef UNIV_DEBUG ut_ad(mutex_own(&dict_sys->mutex)); -#endif - - if (fts_table != NULL) { - char* table_name; - - table_name = fts_get_table_name(fts_table); - str_tmp = ut_strreplace(sql, "%s", table_name); - mem_free(table_name); - } - - if (str_tmp != NULL) { - str = ut_str3cat(fts_sql_begin, str_tmp, fts_sql_end); - mem_free(str_tmp); - } else { - str = ut_str3cat(fts_sql_begin, sql, fts_sql_end); - } - //fprintf(stderr, "%s\n", str); + str = ut_str3cat(fts_sql_begin, sql, fts_sql_end); graph = pars_sql(info, str); ut_a(graph); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index a9fb00c9cef..86d84997140 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -966,20 +966,6 @@ innodb_empty_free_list_algorithm_allowed( || algorithm != SRV_EMPTY_FREE_LIST_BACKOFF); } -/** Get the list of foreign keys referencing a specified table -table. -@param thd The thread handle -@param path Path to the table -@param f_key_list[out] The list of foreign keys - -@return error code or zero for success */ -static -int -innobase_get_parent_fk_list( - THD* thd, - const char* path, - List<FOREIGN_KEY_INFO>* f_key_list) __attribute__((unused)); - /******************************************************************//** Maps a MySQL trx isolation level code to the InnoDB isolation level code @return InnoDB isolation level */ @@ -15011,6 +14997,10 @@ get_foreign_key_info( LEX_STRING* referenced_key_name; LEX_STRING* name = NULL; + if (row_is_mysql_tmp_table_name(foreign->foreign_table_name)) { + return NULL; + } + ptr = dict_remove_db_name(foreign->id); f_key_info.foreign_id = thd_make_lex_string(thd, 0, ptr, (uint) strlen(ptr), 1); @@ -15125,49 +15115,6 @@ fill_foreign_key_list(THD* thd, } } -/** Get the list of foreign keys referencing a specified table -table. -@param thd The thread handle -@param path Path to the table -@param f_key_list[out] The list of foreign keys - -@return error code or zero for success */ -static -int -innobase_get_parent_fk_list( - THD* thd, - const char* path, - List<FOREIGN_KEY_INFO>* f_key_list) -{ - ut_a(strlen(path) <= FN_REFLEN); - char norm_name[FN_REFLEN + 1]; - normalize_table_name(norm_name, path); - - trx_t* parent_trx = check_trx_exists(thd); - parent_trx->op_info = "getting list of referencing foreign keys"; - trx_search_latch_release_if_reserved(parent_trx); - - mutex_enter(&dict_sys->mutex); - - dict_table_t* table - = dict_table_open_on_name(norm_name, TRUE, FALSE, - static_cast<dict_err_ignore_t>( - DICT_ERR_IGNORE_INDEX_ROOT - | DICT_ERR_IGNORE_CORRUPT)); - if (!table) { - mutex_exit(&dict_sys->mutex); - return(HA_ERR_NO_SUCH_TABLE); - } - - fill_foreign_key_list(thd, table, f_key_list); - - dict_table_close(table, TRUE, FALSE); - - mutex_exit(&dict_sys->mutex); - parent_trx->op_info = ""; - return(0); -} - /*******************************************************************//** Gets the list of foreign keys in this table. @return always 0, that is, always succeeds */ diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc index 5c2d65e5799..105c5573ae9 100644 --- a/storage/xtradb/handler/i_s.cc +++ b/storage/xtradb/handler/i_s.cc @@ -3470,6 +3470,7 @@ i_s_fts_index_table_fill_selected( que_t* graph; dberr_t error; fts_fetch_t fetch; + char table_name[MAX_FULL_NAME_LEN]; info = pars_info_create(); @@ -3490,6 +3491,8 @@ i_s_fts_index_table_fill_selected( FTS_INIT_INDEX_TABLE(&fts_table, fts_get_suffix(selected), FTS_INDEX_TABLE, index); + fts_get_table_name(&fts_table, table_name); + pars_info_bind_id(info, true, "table_name", table_name); graph = fts_parse_sql( &fts_table, info, @@ -3497,7 +3500,7 @@ i_s_fts_index_table_fill_selected( "DECLARE CURSOR c IS" " SELECT word, doc_count, first_doc_id, last_doc_id, " "ilist\n" - " FROM %s WHERE word >= :word;\n" + " FROM $table_name WHERE word >= :word;\n" "BEGIN\n" "\n" "OPEN c;\n" diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index 7be4d0380e0..e7605d40464 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2018, MariaDB Corporation. +Copyright (c) 2013, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -841,6 +841,18 @@ fil_op_log_parse_or_replay( only be parsed but not replayed */ ulint log_flags); /*!< in: redo log flags (stored in the page number parameter) */ + +/** Determine whether a table can be accessed in operations that are +not (necessarily) protected by meta-data locks. +(Rollback would generally be protected, but rollback of +FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks +but only by InnoDB table locks, which may be broken by +lock_remove_all_on_table().) +@param[in] table persistent table +checked @return whether the table is accessible */ +UNIV_INTERN bool fil_table_accessible(const dict_table_t* table) + MY_ATTRIBUTE((warn_unused_result, nonnull)); + /** Delete a tablespace and associated .ibd file. @param[in] id tablespace identifier @param[in] drop_ahi whether to drop the adaptive hash index diff --git a/storage/xtradb/include/fts0fts.h b/storage/xtradb/include/fts0fts.h index ce30a17c4b4..7265e42b0ab 100644 --- a/storage/xtradb/include/fts0fts.h +++ b/storage/xtradb/include/fts0fts.h @@ -151,7 +151,6 @@ do { \ (fts_table)->suffix = m_suffix; \ (fts_table)->type = m_type; \ (fts_table)->table_id = m_table->id; \ - (fts_table)->parent = m_table->name; \ (fts_table)->table = m_table; \ } while (0); @@ -160,7 +159,6 @@ do { \ (fts_table)->suffix = m_suffix; \ (fts_table)->type = m_type; \ (fts_table)->table_id = m_index->table->id; \ - (fts_table)->parent = m_index->table->name; \ (fts_table)->table = m_index->table; \ (fts_table)->index_id = m_index->id; \ } while (0); @@ -265,10 +263,6 @@ struct fts_result_t { table id and the index id to generate the column specific FTS auxiliary table name. */ struct fts_table_t { - const char* parent; /*!< Parent table name, this is - required only for the database - name */ - fts_table_type_t type; /*!< The auxiliary table type */ @@ -424,7 +418,6 @@ 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, or NULL */ doc_id_t doc_id) /*!< in: DOC ID to set */ MY_ATTRIBUTE((nonnull(2))); diff --git a/storage/xtradb/include/fts0priv.h b/storage/xtradb/include/fts0priv.h index a3936f54a48..5a4e37556a9 100644 --- a/storage/xtradb/include/fts0priv.h +++ b/storage/xtradb/include/fts0priv.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. 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 @@ -132,16 +133,15 @@ fts_eval_sql( trx_t* trx, /*!< in: transaction */ que_t* graph) /*!< in: Parsed statement */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -/******************************************************************//** -Construct the name of an ancillary FTS table for the given table. -@return own: table name, must be freed with mem_free() */ + +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[out] table_name a name up to MAX_FULL_NAME_LEN +@param[in] dict_locked whether dict_sys->mutex is being held */ UNIV_INTERN -char* -fts_get_table_name( -/*===============*/ - const fts_table_t* - fts_table) /*!< in: FTS aux table info */ - MY_ATTRIBUTE((nonnull, malloc, warn_unused_result)); +void fts_get_table_name(const fts_table_t* fts_table, char* table_name, + bool dict_locked = false) + MY_ATTRIBUTE((nonnull)); /******************************************************************//** Construct the column specification part of the SQL string for selecting the indexed FTS columns for the given table. Adds the necessary bound @@ -597,15 +597,11 @@ fts_get_table_id( FTS_AUX_MIN_TABLE_ID_LENGTH bytes long */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -/******************************************************************//** -Construct the prefix name of an FTS table. -@return own: table name, must be freed with mem_free() */ -UNIV_INTERN -char* -fts_get_table_name_prefix( -/*======================*/ - const fts_table_t* - fts_table) /*!< in: Auxiliary table type */ +/** Construct the name of an internal FTS table for the given table. +@param[in] fts_table metadata on fulltext-indexed table +@param[in] dict_locked whether dict_sys->mutex is being held +@return the prefix, must be freed with ut_free() */ +UNIV_INTERN char* fts_get_table_name_prefix(const fts_table_t* fts_table) MY_ATTRIBUTE((nonnull, malloc, warn_unused_result)); /******************************************************************//** Add node positions. */ diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc index d3c8b9a80bd..6ae7827777a 100644 --- a/storage/xtradb/row/row0ftsort.cc +++ b/storage/xtradb/row/row0ftsort.cc @@ -1503,7 +1503,6 @@ row_fts_merge_insert( ins_ctx.fts_table.type = FTS_INDEX_TABLE; ins_ctx.fts_table.index_id = index->id; ins_ctx.fts_table.table_id = table->id; - ins_ctx.fts_table.parent = index->table->name; ins_ctx.fts_table.table = index->table; space = table->space; diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index 0acfc662cab..3884d767730 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -2083,8 +2083,7 @@ wait_again: false, true, false); if (err == DB_SUCCESS) { - fts_update_next_doc_id( - 0, new_table, old_table->name, max_doc_id); + fts_update_next_doc_id(NULL, new_table, max_doc_id); } } diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index a21e32cb91e..6ee7f702b70 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -3841,7 +3841,7 @@ next_rec: os_thread_sleep(10000000);); table->fts->fts_status |= TABLE_DICT_LOCKED; - fts_update_next_doc_id(trx, table, NULL, 0); + fts_update_next_doc_id(trx, table, 0); fts_cache_clear(table->fts->cache); fts_cache_init(table->fts->cache); table->fts->fts_status &= ~TABLE_DICT_LOCKED; diff --git a/storage/xtradb/ut/ut0timer.cc b/storage/xtradb/ut/ut0timer.cc index 85292cce28c..fdd357e0677 100644 --- a/storage/xtradb/ut/ut0timer.cc +++ b/storage/xtradb/ut/ut0timer.cc @@ -47,6 +47,8 @@ ulonglong (*ut_timer_now)(void) = &ut_timer_none; struct my_timer_unit_info ut_timer; +extern MYSQL_PLUGIN_IMPORT MY_TIMER_INFO sys_timer_info; + /**************************************************************//** Sets up the data required for use of my_timer_* functions. Selects the best timer by high frequency, and tight resolution. @@ -57,30 +59,27 @@ void ut_init_timer(void) /*===============*/ { - MY_TIMER_INFO all_timer_info; - my_timer_init(&all_timer_info); - - if (all_timer_info.cycles.frequency > 1000000 && - all_timer_info.cycles.resolution == 1) { - ut_timer = all_timer_info.cycles; + if (sys_timer_info.cycles.frequency > 1000000 && + sys_timer_info.cycles.resolution == 1) { + ut_timer = sys_timer_info.cycles; ut_timer_now = &my_timer_cycles; - } else if (all_timer_info.nanoseconds.frequency > 1000000 && - all_timer_info.nanoseconds.resolution == 1) { - ut_timer = all_timer_info.nanoseconds; + } else if (sys_timer_info.nanoseconds.frequency > 1000000 && + sys_timer_info.nanoseconds.resolution == 1) { + ut_timer = sys_timer_info.nanoseconds; ut_timer_now = &my_timer_nanoseconds; - } else if (all_timer_info.microseconds.frequency >= 1000000 && - all_timer_info.microseconds.resolution == 1) { - ut_timer = all_timer_info.microseconds; + } else if (sys_timer_info.microseconds.frequency >= 1000000 && + sys_timer_info.microseconds.resolution == 1) { + ut_timer = sys_timer_info.microseconds; ut_timer_now = &my_timer_microseconds; - } else if (all_timer_info.milliseconds.frequency >= 1000 && - all_timer_info.milliseconds.resolution == 1) { - ut_timer = all_timer_info.milliseconds; + } else if (sys_timer_info.milliseconds.frequency >= 1000 && + sys_timer_info.milliseconds.resolution == 1) { + ut_timer = sys_timer_info.milliseconds; ut_timer_now = &my_timer_milliseconds; - } else if (all_timer_info.ticks.frequency >= 1000 && + } else if (sys_timer_info.ticks.frequency >= 1000 && /* Will probably be false */ - all_timer_info.ticks.resolution == 1) { - ut_timer = all_timer_info.ticks; + sys_timer_info.ticks.resolution == 1) { + ut_timer = sys_timer_info.ticks; ut_timer_now = &my_timer_ticks; } else { /* None are acceptable, so leave it as "None", and fill in struct */ |