diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-08-03 15:57:23 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-08-03 15:57:23 +0300 |
commit | 05459706f22b1d9d22abd24e6de3b505d787beb3 (patch) | |
tree | 3e850e0cbf5489fbf36f5c1579248e344bfe2395 /storage/innobase | |
parent | 8ae2a2dbe6fc52d40ec88c325b9a44de52f83f2f (diff) | |
parent | e6a808bec790fdbbf1dc0a6b03fb6c8b6e41dc01 (diff) | |
download | mariadb-git-05459706f22b1d9d22abd24e6de3b505d787beb3.tar.gz |
Merge 10.2 into 10.3
Diffstat (limited to 'storage/innobase')
44 files changed, 656 insertions, 623 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 11dc5b43059..3d8d08573f7 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2012, Facebook Inc. Copyright (c) 2015, 2018, MariaDB Corporation. @@ -65,6 +65,8 @@ Created 10/16/1994 Heikki Tuuri #include "lock0lock.h" #include "zlib.h" #include "srv0start.h" +#include "mysql_com.h" +#include "dict0stats.h" /** Buffered B-tree operation types, introduced as part of delete buffering. */ enum btr_op_t { @@ -781,13 +783,15 @@ btr_cur_will_modify_tree( first record and following compress might delete the record and causes the uppper level node_ptr modification. */ + const ulint n_recs = page_get_n_recs(page); + if (lock_intention <= BTR_INTENTION_BOTH) { ulint margin; /* check delete will cause. (BTR_INTENTION_BOTH or BTR_INTENTION_DELETE) */ /* first, 2nd, 2nd-last and last records are 4 records */ - if (page_get_n_recs(page) < 5) { + if (n_recs < 5) { return(true); } @@ -833,8 +837,7 @@ btr_cur_will_modify_tree( /* Once we invoke the btr_cur_limit_optimistic_insert_debug, we should check it here in advance, since the max allowable records in a page is limited. */ - LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page), - return(true)); + LIMIT_OPTIMISTIC_INSERT_DEBUG(n_recs, return true); /* needs 2 records' space for the case the single split and insert cannot fit. @@ -847,18 +850,16 @@ btr_cur_will_modify_tree( || max_size < rec_size * 2) { return(true); } - /* TODO: optimize this condition for compressed page. - this is based on the worst compress rate. - currently looking only uncompressed page, but we can look - also compressed page page_zip_available() if already in the - buffer pool */ + + /* TODO: optimize this condition for ROW_FORMAT=COMPRESSED. + This is based on the worst case, and we could invoke + page_zip_available() on the block->page.zip. */ /* needs 2 records' space also for worst compress rate. */ if (page_size.is_compressed() && page_zip_empty_size(index->n_fields, page_size.physical()) - < rec_size * 2 + page_get_data_size(page) - + page_dir_calc_reserved_space( - ulint(page_get_n_recs(page)) + 2) + 1) { + <= rec_size * 2 + page_get_data_size(page) + + page_dir_calc_reserved_space(n_recs + 2)) { return(true); } } @@ -893,6 +894,114 @@ btr_cur_need_opposite_intention( return(false); } +/** +@param[in] index b-tree +@return maximum size of a node pointer record in bytes */ +static ulint btr_node_ptr_max_size(const dict_index_t* index) +{ + if (dict_index_is_ibuf(index)) { + /* cannot estimate accurately */ + /* This is universal index for change buffer. + The max size of the entry is about max key length * 2. + (index key + primary key to be inserted to the index) + (The max key length is UNIV_PAGE_SIZE / 16 * 3 at + ha_innobase::max_supported_key_length(), + considering MAX_KEY_LENGTH = 3072 at MySQL imposes + the 3500 historical InnoDB value for 16K page size case.) + For the universal index, node_ptr contains most of the entry. + And 512 is enough to contain ibuf columns and meta-data */ + return srv_page_size / 8 * 3 + 512; + } + + /* Each record has page_no, length of page_no and header. */ + ulint comp = dict_table_is_comp(index->table); + ulint rec_max_size = comp + ? REC_NODE_PTR_SIZE + 1 + REC_N_NEW_EXTRA_BYTES + + UT_BITS_IN_BYTES(index->n_nullable) + : REC_NODE_PTR_SIZE + 2 + REC_N_OLD_EXTRA_BYTES + + 2 * index->n_fields; + + /* Compute the maximum possible record size. */ + for (ulint i = 0; i < dict_index_get_n_unique_in_tree(index); i++) { + const dict_field_t* field + = dict_index_get_nth_field(index, i); + const dict_col_t* col + = dict_field_get_col(field); + ulint field_max_size; + ulint field_ext_max_size; + + /* Determine the maximum length of the index field. */ + + field_max_size = dict_col_get_fixed_size(col, comp); + if (field_max_size) { + /* dict_index_add_col() should guarantee this */ + ut_ad(!field->prefix_len + || field->fixed_len == field->prefix_len); + /* Fixed lengths are not encoded + in ROW_FORMAT=COMPACT. */ + rec_max_size += field_max_size; + continue; + } + + field_max_size = dict_col_get_max_size(col); + if (UNIV_UNLIKELY(!field_max_size)) { + /* SYS_FOREIGN.ID is defined as CHAR in the + InnoDB internal SQL parser, which translates + into the incorrect VARCHAR(0). InnoDB does + not enforce maximum lengths of columns, so + that is why any data can be inserted in the + first place. + + Likewise, SYS_FOREIGN.FOR_NAME, + SYS_FOREIGN.REF_NAME, SYS_FOREIGN_COLS.ID, are + defined as CHAR, and also they are part of a key. */ + + ut_ad(!strcmp(index->table->name.m_name, + "SYS_FOREIGN") + || !strcmp(index->table->name.m_name, + "SYS_FOREIGN_COLS")); + ut_ad(!comp); + + rec_max_size += (srv_page_size == UNIV_PAGE_SIZE_MAX) + ? REDUNDANT_REC_MAX_DATA_SIZE + : page_get_free_space_of_empty(FALSE) / 2; + } else if (field_max_size == NAME_LEN && i == 1 + && (!strcmp(index->table->name.m_name, + TABLE_STATS_NAME) + || !strcmp(index->table->name.m_name, + INDEX_STATS_NAME))) { + ut_ad(!strcmp(field->name, "table_name")); + /* Interpret "table_name" as VARCHAR(199) even + if it was incorrectly defined as VARCHAR(64). + While the caller of ha_innobase enforces the + maximum length on any data written, the InnoDB + internal SQL parser will happily write as much + data as is provided. The purpose of this hack + is to avoid InnoDB hangs after persistent + statistics on partitioned tables are + deleted. */ + field_max_size = 199 * SYSTEM_CHARSET_MBMAXLEN; + } + field_ext_max_size = field_max_size < 256 ? 1 : 2; + + if (field->prefix_len + && field->prefix_len < field_max_size) { + field_max_size = field->prefix_len; + } + + if (comp) { + /* Add the extra size for ROW_FORMAT=COMPACT. + For ROW_FORMAT=REDUNDANT, these bytes were + added to rec_max_size before this loop. */ + rec_max_size += field_ext_max_size; + } + + rec_max_size += field_max_size; + } + + return rec_max_size; +} + /********************************************************************//** Searches an index tree and positions a tree cursor on a given level. NOTE: n_fields_cmp in tuple must be set so that it cannot be compared @@ -1218,7 +1327,7 @@ btr_cur_search_to_nth_level_func( page_id_t page_id(index->table->space->id, index->page); if (root_leaf_rw_latch == RW_X_LATCH) { - node_ptr_max_size = dict_index_node_ptr_max_size(index); + node_ptr_max_size = btr_node_ptr_max_size(index); } up_match = 0; @@ -2327,7 +2436,7 @@ btr_cur_open_at_index_side_func( const page_size_t page_size(index->table->space->flags); if (root_leaf_rw_latch == RW_X_LATCH) { - node_ptr_max_size = dict_index_node_ptr_max_size(index); + node_ptr_max_size = btr_node_ptr_max_size(index); } height = ULINT_UNDEFINED; @@ -2685,7 +2794,7 @@ btr_cur_open_at_rnd_pos_func( dberr_t err = DB_SUCCESS; if (root_leaf_rw_latch == RW_X_LATCH) { - node_ptr_max_size = dict_index_node_ptr_max_size(index); + node_ptr_max_size = btr_node_ptr_max_size(index); } height = ULINT_UNDEFINED; @@ -5657,23 +5766,45 @@ discard_page: } } - page_cur_delete_rec(btr_cur_get_page_cur(cursor), index, offsets, mtr); + /* SPATIAL INDEX never use SX locks; we can allow page merges + while holding X lock on the spatial index tree. + Do not allow merges of non-leaf B-tree pages unless it is + safe to do so. */ + { + const bool allow_merge = page_is_leaf(page) + || dict_index_is_spatial(index) + || btr_cur_will_modify_tree( + index, page, BTR_INTENTION_DELETE, rec, + btr_node_ptr_max_size(index), + block->page.size, mtr); + page_cur_delete_rec(btr_cur_get_page_cur(cursor), index, + offsets, mtr); #ifdef UNIV_ZIP_DEBUG - ut_a(!page_zip || page_zip_validate(page_zip, page, index)); + ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ -return_after_reservations: - /* btr_check_node_ptr() needs parent block latched */ - ut_ad(!parent_latched || btr_check_node_ptr(index, block, mtr)); + ut_ad(!parent_latched + || btr_check_node_ptr(index, block, mtr)); + + if (!ret && btr_cur_compress_recommendation(cursor, mtr)) { + if (UNIV_LIKELY(allow_merge)) { + ret = btr_cur_compress_if_useful( + cursor, FALSE, mtr); + } else { + ib::warn() << "Not merging page " + << block->page.id + << " in index " << index->name + << " of " << index->table->name; + ut_ad(!"MDEV-14637"); + } + } + } +return_after_reservations: *err = DB_SUCCESS; mem_heap_free(heap); - if (ret == FALSE) { - ret = btr_cur_compress_if_useful(cursor, FALSE, mtr); - } - if (!srv_read_only_mode && page_is_leaf(page) && !dict_index_is_online_ddl(index)) { diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index 27a45654966..f932195897c 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -124,7 +124,7 @@ buf_buddy_stamp_free( buf_buddy_free_t* buf, /*!< in/out: block to stamp */ ulint i) /*!< in: block size */ { - ut_d(memset(buf, static_cast<int>(i), BUF_BUDDY_LOW << i)); + ut_d(memset(&buf->stamp.bytes, int(i), BUF_BUDDY_LOW << i)); buf_buddy_mem_invalid(buf, i); mach_write_to_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET, BUF_BUDDY_STAMP_FREE); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index f053c170c0e..bd64334c3ba 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2258,7 +2258,7 @@ buf_page_realloc( mutex_enter(&new_block->mutex); memcpy(new_block->frame, block->frame, srv_page_size); - memcpy(&new_block->page, &block->page, sizeof block->page); + new (&new_block->page) buf_page_t(block->page); /* relocate LRU list */ ut_ad(block->page.in_LRU_list); @@ -3389,7 +3389,7 @@ buf_relocate( } #endif /* UNIV_DEBUG */ - memcpy(dpage, bpage, sizeof *dpage); + new (dpage) buf_page_t(*bpage); /* Important that we adjust the hazard pointer before removing bpage from LRU list. */ diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index a0c4baad64d..7ede67fd0e4 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -262,7 +262,7 @@ buf_dump( #define SHOULD_QUIT() (SHUTTING_DOWN() && obey_shutdown) char full_filename[OS_FILE_MAX_PATH]; - char tmp_filename[OS_FILE_MAX_PATH]; + char tmp_filename[OS_FILE_MAX_PATH + sizeof "incomplete"]; char now[32]; FILE* f; ulint i; diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index ebd5c2a828b..125c5beb47c 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -1610,7 +1610,7 @@ func_exit: } else if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) { b = buf_page_alloc_descriptor(); ut_a(b); - memcpy(b, bpage, sizeof *b); + new (b) buf_page_t(*bpage); } ut_ad(buf_pool_mutex_own(buf_pool)); diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc index 949bbbc0d74..69038d4cb77 100644 --- a/storage/innobase/dict/dict0defrag_bg.cc +++ b/storage/innobase/dict/dict0defrag_bg.cc @@ -39,27 +39,13 @@ static ib_mutex_t defrag_pool_mutex; static mysql_pfs_key_t defrag_pool_mutex_key; #endif -/** Indices whose defrag stats need to be saved to persistent storage.*/ -struct defrag_pool_item_t { - table_id_t table_id; - index_id_t index_id; -}; - -/** Allocator type, used by std::vector */ -typedef ut_allocator<defrag_pool_item_t> - defrag_pool_allocator_t; - -/** The multitude of tables to be defragmented- an STL vector */ -typedef std::vector<defrag_pool_item_t, defrag_pool_allocator_t> - defrag_pool_t; - /** Iterator type for iterating over the elements of objects of type defrag_pool_t. */ typedef defrag_pool_t::iterator defrag_pool_iterator_t; /** Pool where we store information on which tables are to be processed by background defragmentation. */ -static defrag_pool_t* defrag_pool; +defrag_pool_t defrag_pool; extern bool dict_stats_start_shutdown; @@ -70,14 +56,6 @@ dict_defrag_pool_init(void) /*=======================*/ { ut_ad(!srv_read_only_mode); - /* JAN: TODO: MySQL 5.7 PSI - const PSI_memory_key key2 = mem_key_dict_defrag_pool_t; - - defrag_pool = UT_NEW(defrag_pool_t(defrag_pool_allocator_t(key2)), key2); - - recalc_pool->reserve(RECALC_POOL_INITIAL_SLOTS); - */ - defrag_pool = new std::vector<defrag_pool_item_t, defrag_pool_allocator_t>(); /* We choose SYNC_STATS_DEFRAG to be below SYNC_FSP_PAGE. */ mutex_create(LATCH_ID_DEFRAGMENT_MUTEX, &defrag_pool_mutex); @@ -92,10 +70,7 @@ dict_defrag_pool_deinit(void) { ut_ad(!srv_read_only_mode); - defrag_pool->clear(); mutex_free(&defrag_pool_mutex); - - UT_DELETE(defrag_pool); } /*****************************************************************//** @@ -115,16 +90,16 @@ dict_stats_defrag_pool_get( mutex_enter(&defrag_pool_mutex); - if (defrag_pool->empty()) { + if (defrag_pool.empty()) { mutex_exit(&defrag_pool_mutex); return(false); } - defrag_pool_item_t& item = defrag_pool->back(); + defrag_pool_item_t& item = defrag_pool.back(); *table_id = item.table_id; *index_id = item.index_id; - defrag_pool->pop_back(); + defrag_pool.pop_back(); mutex_exit(&defrag_pool_mutex); @@ -149,8 +124,8 @@ dict_stats_defrag_pool_add( mutex_enter(&defrag_pool_mutex); /* quit if already in the list */ - for (defrag_pool_iterator_t iter = defrag_pool->begin(); - iter != defrag_pool->end(); + for (defrag_pool_iterator_t iter = defrag_pool.begin(); + iter != defrag_pool.end(); ++iter) { if ((*iter).table_id == index->table->id && (*iter).index_id == index->id) { @@ -161,7 +136,7 @@ dict_stats_defrag_pool_add( item.table_id = index->table->id; item.index_id = index->id; - defrag_pool->push_back(item); + defrag_pool.push_back(item); mutex_exit(&defrag_pool_mutex); @@ -183,14 +158,14 @@ dict_stats_defrag_pool_del( mutex_enter(&defrag_pool_mutex); - defrag_pool_iterator_t iter = defrag_pool->begin(); - while (iter != defrag_pool->end()) { + defrag_pool_iterator_t iter = defrag_pool.begin(); + while (iter != defrag_pool.end()) { if ((table && (*iter).table_id == table->id) || (index && (*iter).table_id == index->table->id && (*iter).index_id == index->id)) { /* erase() invalidates the iterator */ - iter = defrag_pool->erase(iter); + iter = defrag_pool.erase(iter); if (index) break; } else { @@ -252,7 +227,7 @@ void dict_defrag_process_entries_from_defrag_pool() /*==========================================*/ { - while (defrag_pool->size() && !dict_stats_start_shutdown) { + while (defrag_pool.size() && !dict_stats_start_shutdown) { dict_stats_process_entry_from_defrag_pool(); } } diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index f088e6d356c..51190ff2ef6 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -2089,93 +2089,6 @@ dict_col_name_is_reserved( } /****************************************************************//** -Return maximum size of the node pointer record. -@return maximum size of the record in bytes */ -ulint -dict_index_node_ptr_max_size( -/*=========================*/ - const dict_index_t* index) /*!< in: index */ -{ - ulint comp; - ulint i; - /* maximum possible storage size of a record */ - ulint rec_max_size; - - if (dict_index_is_ibuf(index)) { - /* cannot estimate accurately */ - /* This is universal index for change buffer. - The max size of the entry is about max key length * 2. - (index key + primary key to be inserted to the index) - (The max key length is srv_page_size / 16 * 3 at - ha_innobase::max_supported_key_length(), - considering MAX_KEY_LENGTH = 3072 at MySQL imposes - the 3500 historical InnoDB value for 16K page size case.) - For the universal index, node_ptr contains most of the entry. - And 512 is enough to contain ibuf columns and meta-data */ - return(srv_page_size / 8 * 3 + 512); - } - - comp = dict_table_is_comp(index->table); - - /* Each record has page_no, length of page_no and header. */ - rec_max_size = comp - ? REC_NODE_PTR_SIZE + 1 + REC_N_NEW_EXTRA_BYTES - : REC_NODE_PTR_SIZE + 2 + REC_N_OLD_EXTRA_BYTES; - - if (comp) { - /* Include the "null" flags in the - maximum possible record size. */ - rec_max_size += UT_BITS_IN_BYTES(unsigned(index->n_nullable)); - } else { - /* For each column, include a 2-byte offset and a - "null" flag. */ - rec_max_size += 2 * unsigned(index->n_fields); - } - - /* Compute the maximum possible record size. */ - for (i = 0; i < dict_index_get_n_unique_in_tree(index); i++) { - const dict_field_t* field - = dict_index_get_nth_field(index, i); - const dict_col_t* col - = dict_field_get_col(field); - ulint field_max_size; - ulint field_ext_max_size; - - /* Determine the maximum length of the index field. */ - - field_max_size = dict_col_get_fixed_size(col, comp); - if (field_max_size) { - /* dict_index_add_col() should guarantee this */ - ut_ad(!field->prefix_len - || field->fixed_len == field->prefix_len); - /* Fixed lengths are not encoded - in ROW_FORMAT=COMPACT. */ - rec_max_size += field_max_size; - continue; - } - - field_max_size = dict_col_get_max_size(col); - field_ext_max_size = field_max_size < 256 ? 1 : 2; - - if (field->prefix_len - && field->prefix_len < field_max_size) { - field_max_size = field->prefix_len; - } - - if (comp) { - /* Add the extra size for ROW_FORMAT=COMPACT. - For ROW_FORMAT=REDUNDANT, these bytes were - added to rec_max_size before this loop. */ - rec_max_size += field_ext_max_size; - } - - rec_max_size += field_max_size; - } - - return(rec_max_size); -} - -/****************************************************************//** If a record of this index might not fit on a single B-tree page, return TRUE. @return TRUE if the index record could become too big */ @@ -6460,8 +6373,17 @@ dict_table_schema_check( compare column types and flags */ /* check length for exact match */ - if (req_schema->columns[i].len != table->cols[j].len) { - + if (req_schema->columns[i].len == table->cols[j].len) { + } else if (!strcmp(req_schema->table_name, TABLE_STATS_NAME) + || !strcmp(req_schema->table_name, + INDEX_STATS_NAME)) { + ut_ad(table->cols[j].len < req_schema->columns[i].len); + ib::warn() << "Table " << req_schema->table_name + << " has length mismatch in the" + << " column name " + << req_schema->columns[i].name + << ". Please run mysql_upgrade"; + } else { CREATE_TYPES_NAMES(); snprintf(errstr, errstr_sz, diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 51dcdc9e140..69eebab8e17 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2009, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2009, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2015, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -108,9 +108,7 @@ where n=1..n_uniq. @} */ /* names of the tables from the persistent statistics storage */ -#define TABLE_STATS_NAME "mysql/innodb_table_stats" #define TABLE_STATS_NAME_PRINT "mysql.innodb_table_stats" -#define INDEX_STATS_NAME "mysql/innodb_index_stats" #define INDEX_STATS_NAME_PRINT "mysql.innodb_index_stats" #ifdef UNIV_STATS_DEBUG @@ -181,7 +179,7 @@ dict_stats_persistent_storage_check( DATA_NOT_NULL, 192}, {"table_name", DATA_VARMYSQL, - DATA_NOT_NULL, 192}, + DATA_NOT_NULL, 597}, {"last_update", DATA_FIXBINARY, DATA_NOT_NULL, 4}, @@ -209,7 +207,7 @@ dict_stats_persistent_storage_check( DATA_NOT_NULL, 192}, {"table_name", DATA_VARMYSQL, - DATA_NOT_NULL, 192}, + DATA_NOT_NULL, 597}, {"index_name", DATA_VARMYSQL, DATA_NOT_NULL, 192}, diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc index 6fde5654dd1..f15e98b8a4d 100644 --- a/storage/innobase/dict/dict0stats_bg.cc +++ b/storage/innobase/dict/dict0stats_bg.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2018, 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 @@ -32,6 +32,12 @@ Created Apr 25, 2012 Vasil Dimov #include "srv0start.h" #include "ut0new.h" #include "fil0fil.h" +#ifdef WITH_WSREP +# include "mysql/service_wsrep.h" +# include "wsrep.h" +# include "log.h" +# include "wsrep_mysqld.h" +#endif #include <vector> @@ -76,41 +82,31 @@ typedef recalc_pool_t::iterator /** Pool where we store information on which tables are to be processed by background statistics gathering. */ -static recalc_pool_t* recalc_pool; - - -/*****************************************************************//** -Initialize the recalc pool, called once during thread initialization. */ -static -void -dict_stats_recalc_pool_init() -/*=========================*/ -{ - ut_ad(!srv_read_only_mode); - /* JAN: TODO: MySQL 5.7 PSI - const PSI_memory_key key = mem_key_dict_stats_bg_recalc_pool_t; - - recalc_pool = UT_NEW(recalc_pool_t(recalc_pool_allocator_t(key)), key); - - recalc_pool->reserve(RECALC_POOL_INITIAL_SLOTS); - */ - recalc_pool = new std::vector<table_id_t, recalc_pool_allocator_t>(); -} +static recalc_pool_t recalc_pool; +/** Whether the global data structures have been initialized */ +static bool stats_initialised; /*****************************************************************//** Free the resources occupied by the recalc pool, called once during thread de-initialization. */ -static -void -dict_stats_recalc_pool_deinit() -/*===========================*/ +static void dict_stats_recalc_pool_deinit() { ut_ad(!srv_read_only_mode); - recalc_pool->clear(); - - UT_DELETE(recalc_pool); - recalc_pool = NULL; + recalc_pool.clear(); + defrag_pool.clear(); + /* + recalc_pool may still have its buffer allocated. It will free it when + its destructor is called. + The problem is, memory leak detector is run before the recalc_pool's + destructor is invoked, and will report recalc_pool's buffer as leaked + memory. To avoid that, we force recalc_pool to surrender its buffer + to empty_pool object, which will free it when leaving this function: + */ + recalc_pool_t recalc_empty_pool; + defrag_pool_t defrag_empty_pool; + recalc_pool.swap(recalc_empty_pool); + defrag_pool.swap(defrag_empty_pool); } /*****************************************************************//** @@ -130,8 +126,8 @@ dict_stats_recalc_pool_add( mutex_enter(&recalc_pool_mutex); /* quit if already in the list */ - for (recalc_pool_iterator_t iter = recalc_pool->begin(); - iter != recalc_pool->end(); + for (recalc_pool_iterator_t iter = recalc_pool.begin(); + iter != recalc_pool.end(); ++iter) { if (*iter == table->id) { @@ -140,18 +136,25 @@ dict_stats_recalc_pool_add( } } - recalc_pool->push_back(table->id); + recalc_pool.push_back(table->id); mutex_exit(&recalc_pool_mutex); os_event_set(dict_stats_event); } +#ifdef WITH_WSREP +/** Update the table modification counter and if necessary, +schedule new estimates for table and index statistics to be calculated. +@param[in,out] table persistent or temporary table +@param[in] thd current session */ +void dict_stats_update_if_needed(dict_table_t* table, THD* thd) +#else /** Update the table modification counter and if necessary, schedule new estimates for table and index statistics to be calculated. @param[in,out] table persistent or temporary table */ -void -dict_stats_update_if_needed(dict_table_t* table) +void dict_stats_update_if_needed_func(dict_table_t* table) +#endif { ut_ad(table->stat_initialized); ut_ad(!mutex_own(&dict_sys->mutex)); @@ -163,6 +166,15 @@ dict_stats_update_if_needed(dict_table_t* table) if (counter > n_rows / 10 /* 10% */ && dict_stats_auto_recalc_is_enabled(table)) { +#ifdef WITH_WSREP + if (thd && wsrep_on(thd) && wsrep_thd_is_BF(thd, 0)) { + WSREP_DEBUG("Avoiding background statistics" + " calculation for table %s", + table->name.m_name); + return; + } +#endif /* WITH_WSREP */ + dict_stats_recalc_pool_add(table); table->stat_modified_counter = 0; } @@ -200,14 +212,14 @@ dict_stats_recalc_pool_get( mutex_enter(&recalc_pool_mutex); - if (recalc_pool->empty()) { + if (recalc_pool.empty()) { mutex_exit(&recalc_pool_mutex); return(false); } - *id = recalc_pool->at(0); + *id = recalc_pool.at(0); - recalc_pool->erase(recalc_pool->begin()); + recalc_pool.erase(recalc_pool.begin()); mutex_exit(&recalc_pool_mutex); @@ -229,13 +241,13 @@ dict_stats_recalc_pool_del( ut_ad(table->id > 0); - for (recalc_pool_iterator_t iter = recalc_pool->begin(); - iter != recalc_pool->end(); + for (recalc_pool_iterator_t iter = recalc_pool.begin(); + iter != recalc_pool.end(); ++iter) { if (*iter == table->id) { /* erase() invalidates the iterator */ - recalc_pool->erase(iter); + recalc_pool.erase(iter); break; } } @@ -274,7 +286,6 @@ dict_stats_thread_init() dict_stats_event = os_event_create(0); dict_stats_shutdown_event = os_event_create(0); - ut_d(dict_stats_disabled_event = os_event_create(0)); /* The recalc_pool_mutex is acquired from: @@ -293,9 +304,8 @@ dict_stats_thread_init() mutex_create(LATCH_ID_RECALC_POOL, &recalc_pool_mutex); - dict_stats_recalc_pool_init(); dict_defrag_pool_init(); - + stats_initialised = true; } /*****************************************************************//** @@ -308,10 +318,12 @@ dict_stats_thread_deinit() ut_a(!srv_read_only_mode); ut_ad(!srv_dict_stats_thread_active); - if (recalc_pool == NULL) { + if (!stats_initialised) { return; } + stats_initialised = false; + dict_stats_recalc_pool_deinit(); dict_defrag_pool_deinit(); diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc index 82c4438196b..d6695cec5be 100644 --- a/storage/innobase/fts/fts0ast.cc +++ b/storage/innobase/fts/fts0ast.cc @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2018, 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 @@ -28,6 +29,7 @@ Created 2007/3/16 Sunny Bains. #include "fts0ast.h" #include "fts0pars.h" #include "fts0fts.h" +#include "row0sel.h" /* The FTS ast visit pass. */ enum fts_ast_visit_pass_t { @@ -602,6 +604,7 @@ fts_ast_visit( bool revisit = false; bool will_be_ignored = false; fts_ast_visit_pass_t visit_pass = FTS_PASS_FIRST; + const trx_t* trx = node->trx; start_node = node->list.head; @@ -700,6 +703,10 @@ fts_ast_visit( } } + if (trx_is_interrupted(trx)) { + return DB_INTERRUPTED; + } + if (revisit) { /* Exist pass processes the skipped FTS_EXIST operation. */ for (node = start_node; diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index d874725c374..7c26614b309 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -202,7 +202,7 @@ FTS auxiliary INDEX table and clear the cache at the end. @param[in,out] sync sync state @param[in] unlock_cache whether unlock cache lock when write node @param[in] wait whether wait when a sync is in progress -@param[in] has_dict whether has dict operation lock +@param[in] has_dict whether has dict operation lock @return DB_SUCCESS if all OK */ static dberr_t @@ -860,37 +860,28 @@ fts_drop_index( err = fts_drop_index_tables(trx, index); - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry){ - fts_free(table); - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + + fts_free(table); + return(err); } - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry){ - current_doc_id = table->fts->cache->next_doc_id; - first_doc_id = table->fts->cache->first_doc_id; - fts_cache_clear(table->fts->cache); - fts_cache_destroy(table->fts->cache); - table->fts->cache = fts_cache_create(table); - table->fts->cache->next_doc_id = current_doc_id; - table->fts->cache->first_doc_id = first_doc_id; - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + + current_doc_id = table->fts->cache->next_doc_id; + first_doc_id = table->fts->cache->first_doc_id; + fts_cache_clear(table->fts->cache); + fts_cache_destroy(table->fts->cache); + table->fts->cache = fts_cache_create(table); + table->fts->cache->next_doc_id = current_doc_id; + table->fts->cache->first_doc_id = first_doc_id; } else { fts_cache_t* cache = table->fts->cache; fts_index_cache_t* index_cache; @@ -900,18 +891,14 @@ fts_drop_index( index_cache = fts_find_index_cache(cache, index); if (index_cache != NULL) { - for(;;) { - bool retry = false; - if (index->index_fts_syncing) { - retry = true; - } - if (!retry && index_cache->words) { - fts_words_free(index_cache->words); - rbt_free(index_cache->words); - break; - } + while (index->index_fts_syncing + && !trx_is_interrupted(trx)) { DICT_BG_YIELD(trx); } + if (index_cache->words) { + fts_words_free(index_cache->words); + rbt_free(index_cache->words); + } ib_vector_remove(cache->indexes, *(void**) index_cache); } @@ -4048,6 +4035,9 @@ fts_sync_write_words( word = rbt_value(fts_tokenizer_word_t, rbt_node); + DBUG_EXECUTE_IF("fts_instrument_write_words_before_select_index", + os_thread_sleep(300000);); + selected = fts_select_index( index_cache->charset, word->text.f_str, word->text.f_len); @@ -4332,7 +4322,7 @@ FTS auxiliary INDEX table and clear the cache at the end. @param[in,out] sync sync state @param[in] unlock_cache whether unlock cache lock when write node @param[in] wait whether wait when a sync is in progress -@param[in] has_dict whether has dict operation lock +@param[in] has_dict whether has dict operation lock @return DB_SUCCESS if all OK */ static dberr_t @@ -4398,15 +4388,13 @@ begin_sync: continue; } + DBUG_EXECUTE_IF("fts_instrument_sync_before_syncing", + os_thread_sleep(300000);); index_cache->index->index_fts_syncing = true; - DBUG_EXECUTE_IF("fts_instrument_sync_sleep_drop_waits", - os_thread_sleep(10000000); - ); error = fts_sync_index(sync, index_cache); - if (error != DB_SUCCESS && !sync->interrupted) { - + if (error != DB_SUCCESS) { goto end_sync; } } @@ -4441,8 +4429,8 @@ end_sync: } rw_lock_x_lock(&cache->lock); - /* Clear fts syncing flags of any indexes incase sync is - interrupeted */ + /* Clear fts syncing flags of any indexes in case sync is + interrupted */ for (i = 0; i < ib_vector_size(cache->indexes); ++i) { static_cast<fts_index_cache_t*>( ib_vector_get(cache->indexes, i)) diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 4d93451a40d..77115049903 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -62,12 +62,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; -#if 0 -/** Check each table in round robin to see whether they'd -need to be "optimized" */ -static ulint fts_optimize_sync_iterator = 0; -#endif - /** State of a table within the optimization sub system. */ enum fts_state_t { FTS_STATE_LOADED, @@ -79,17 +73,11 @@ enum fts_state_t { /** FTS optimize thread message types. */ enum fts_msg_type_t { - FTS_MSG_START, /*!< Start optimizing thread */ - - FTS_MSG_PAUSE, /*!< Pause optimizing thread */ - FTS_MSG_STOP, /*!< Stop optimizing and exit thread */ FTS_MSG_ADD_TABLE, /*!< Add table to the optimize thread's work queue */ - FTS_MSG_OPTIMIZE_TABLE, /*!< Optimize a table */ - FTS_MSG_DEL_TABLE, /*!< Remove a table from the optimize threads work queue */ FTS_MSG_SYNC_TABLE /*!< Sync fts cache of a table */ @@ -234,7 +222,7 @@ struct fts_msg_t { /** The number of words to read and optimize in a single pass. */ ulong fts_num_word_optimize; -// FIXME +/** Whether to enable additional FTS diagnostic printout. */ char fts_enable_diag_print; /** ZLib compressed block size.*/ @@ -2554,12 +2542,9 @@ fts_optimize_create_msg( return(msg); } -/**********************************************************************//** -Add the table to add to the OPTIMIZER's list. */ -void -fts_optimize_add_table( -/*===================*/ - dict_table_t* table) /*!< in: table to add */ +/** Add the table to add to the OPTIMIZER's list. +@param[in] table table to add */ +void fts_optimize_add_table(dict_table_t* table) { fts_msg_t* msg; @@ -2575,28 +2560,6 @@ fts_optimize_add_table( ib_wqueue_add(fts_optimize_wq, msg, msg->heap); } -#if 0 -/**********************************************************************//** -Optimize a table. */ -static -void -fts_optimize_do_table( -/*==================*/ - dict_table_t* table) /*!< in: table to optimize */ -{ - fts_msg_t* msg; - - /* Optimizer thread could be shutdown */ - if (!fts_optimize_wq) { - return; - } - - msg = fts_optimize_create_msg(FTS_MSG_OPTIMIZE_TABLE, table); - - ib_wqueue_add(fts_optimize_wq, msg, msg->heap); -} -#endif - /**********************************************************************//** Remove the table from the OPTIMIZER's list. We do wait for acknowledgement from the consumer of the message. */ @@ -2672,53 +2635,6 @@ fts_optimize_request_sync_table( } /**********************************************************************//** -Find the slot for a particular table. -@return slot if found else NULL. */ -static -fts_slot_t* -fts_optimize_find_slot( -/*===================*/ - ib_vector_t* tables, /*!< in: vector of tables */ - const dict_table_t* table) /*!< in: table to add */ -{ - 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)); - - if (slot->table == table) { - return(slot); - } - } - - return(NULL); -} - -/**********************************************************************//** -Start optimizing table. */ -static -void -fts_optimize_start_table( -/*=====================*/ - ib_vector_t* tables, /*!< in/out: vector of tables */ - dict_table_t* table) /*!< in: table to optimize */ -{ - fts_slot_t* slot; - - slot = fts_optimize_find_slot(tables, table); - - if (slot == NULL) { - ib::error() << "Table " << table->name << " not registered" - " with the optimize thread."; - } else { - slot->last_run = 0; - slot->completed = 0; - } -} - -/**********************************************************************//** Add the table to the vector if it doesn't already exist. */ static ibool @@ -2900,57 +2816,6 @@ fts_is_sync_needed( return(false); } -#if 0 -/*********************************************************************//** -Check whether a table needs to be optimized. */ -static -void -fts_optimize_need_sync( -/*===================*/ - ib_vector_t* tables) /*!< in: list of tables */ -{ - dict_table_t* table = NULL; - fts_slot_t* slot; - ulint num_table = ib_vector_size(tables); - - if (!num_table) { - return; - } - - if (fts_optimize_sync_iterator >= num_table) { - fts_optimize_sync_iterator = 0; - } - - slot = ib_vector_get(tables, fts_optimize_sync_iterator); - table = slot->table; - - if (!table) { - return; - } - - ut_ad(table->fts); - - if (table->fts->cache) { - ulint deleted = table->fts->cache->deleted; - - if (table->fts->cache->added - >= fts_optimize_add_threshold) { - fts_sync_table(table); - } else if (deleted >= fts_optimize_delete_threshold) { - fts_optimize_do_table(table); - - mutex_enter(&table->fts->cache->deleted_lock); - table->fts->cache->deleted -= deleted; - mutex_exit(&table->fts->cache->deleted_lock); - } - } - - fts_optimize_sync_iterator++; - - return; -} -#endif - /** Sync fts cache of a table @param[in] table_id table id */ void @@ -2963,7 +2828,7 @@ fts_optimize_sync_table( if (table) { if (dict_table_has_fts_index(table) && table->fts->cache) { - fts_sync_table(table, true, false, true); + fts_sync_table(table, true, false, false); } dict_table_close(table, FALSE, FALSE); @@ -3031,8 +2896,7 @@ DECLARE_THREAD(fts_optimize_thread)( fts_msg_t* msg; msg = static_cast<fts_msg_t*>( - ib_wqueue_timedwait(wq, - FTS_QUEUE_WAIT_IN_USECS)); + ib_wqueue_timedwait(wq, FTS_QUEUE_WAIT_IN_USECS)); /* Timeout ? */ if (msg == NULL) { @@ -3044,12 +2908,6 @@ DECLARE_THREAD(fts_optimize_thread)( } switch (msg->type) { - case FTS_MSG_START: - break; - - case FTS_MSG_PAUSE: - break; - case FTS_MSG_STOP: done = TRUE; break; @@ -3064,15 +2922,6 @@ DECLARE_THREAD(fts_optimize_thread)( } break; - case FTS_MSG_OPTIMIZE_TABLE: - if (!done) { - fts_optimize_start_table( - fts_slots, - static_cast<dict_table_t*>( - msg->ptr)); - } - break; - case FTS_MSG_DEL_TABLE: if (fts_optimize_del_table( fts_slots, static_cast<fts_msg_del_t*>( @@ -3087,6 +2936,10 @@ DECLARE_THREAD(fts_optimize_thread)( break; case FTS_MSG_SYNC_TABLE: + DBUG_EXECUTE_IF( + "fts_instrument_msg_sync_sleep", + os_thread_sleep(300000);); + fts_optimize_sync_table( *static_cast<table_id_t*>(msg->ptr)); break; @@ -3149,7 +3002,7 @@ fts_optimize_init(void) ut_ad(!srv_read_only_mode); /* For now we only support one optimize thread. */ - ut_a(fts_optimize_wq == NULL); + ut_a(!fts_optimize_wq); /* Create FTS optimize work queue */ fts_optimize_wq = ib_wqueue_create(); diff --git a/storage/innobase/fts/fts0pars.cc b/storage/innobase/fts/fts0pars.cc index e4d1bba2be6..56cc8d6052c 100644 --- a/storage/innobase/fts/fts0pars.cc +++ b/storage/innobase/fts/fts0pars.cc @@ -88,7 +88,7 @@ extern int fts_lexer(YYSTYPE*, fts_lexer_t*); extern int fts_blexer(YYSTYPE*, yyscan_t); extern int fts_tlexer(YYSTYPE*, yyscan_t); -typedef int (*fts_scan)(); + extern int ftserror(const char* p); @@ -103,8 +103,8 @@ extern int ftserror(const char* p); #define YYTOKENFREE(token) fts_ast_string_free((token)) -typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner); -typedef int (*fts_scanner)(); + +typedef int (*fts_scanner)(YYSTYPE* val, yyscan_t yyscanner); struct fts_lexer_t { fts_scanner scanner; @@ -1948,7 +1948,7 @@ fts_lexer_create( reinterpret_cast<const char*>(query), static_cast<int>(query_len), fts_lexer->yyscanner); - fts_lexer->scanner = reinterpret_cast<fts_scan>(fts_blexer); + fts_lexer->scanner = fts_blexer; /* FIXME: Debugging */ /* fts0bset_debug(1 , fts_lexer->yyscanner); */ } else { @@ -1957,7 +1957,7 @@ fts_lexer_create( reinterpret_cast<const char*>(query), static_cast<int>(query_len), fts_lexer->yyscanner); - fts_lexer->scanner = reinterpret_cast<fts_scan>(fts_tlexer); + fts_lexer->scanner = fts_tlexer; } return(fts_lexer); @@ -1971,7 +1971,7 @@ fts_lexer_free( /*===========*/ fts_lexer_t* fts_lexer) { - if (fts_lexer->scanner == (fts_scan) fts_blexer) { + if (fts_lexer->scanner == fts_blexer) { fts0blex_destroy(fts_lexer->yyscanner); } else { fts0tlex_destroy(fts_lexer->yyscanner); @@ -1988,9 +1988,9 @@ fts_lexer( YYSTYPE* val, fts_lexer_t* fts_lexer) { - fts_scanner_alt func_ptr; + fts_scanner func_ptr; - func_ptr = (fts_scanner_alt) fts_lexer->scanner; + func_ptr = fts_lexer->scanner; return(func_ptr(val, fts_lexer->yyscanner)); } diff --git a/storage/innobase/fts/fts0pars.y b/storage/innobase/fts/fts0pars.y index 1f4ec9922e3..4db72ca65ad 100644 --- a/storage/innobase/fts/fts0pars.y +++ b/storage/innobase/fts/fts0pars.y @@ -36,7 +36,7 @@ extern int fts_lexer(YYSTYPE*, fts_lexer_t*); extern int fts_blexer(YYSTYPE*, yyscan_t); extern int fts_tlexer(YYSTYPE*, yyscan_t); -typedef int (*fts_scan)(); + extern int ftserror(const char* p); @@ -49,8 +49,8 @@ extern int ftserror(const char* p); #define YYPARSE_PARAM state #define YYLEX_PARAM ((fts_ast_state_t*) state)->lexer -typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner); -typedef int (*fts_scanner)(); + +typedef int (*fts_scanner)(YYSTYPE* val, yyscan_t yyscanner); struct fts_lexer_struct { fts_scanner scanner; @@ -238,13 +238,13 @@ fts_lexer_create( if (boolean_mode) { fts0blex_init(&fts_lexer->yyscanner); fts0b_scan_bytes((char*) query, (int) query_len, fts_lexer->yyscanner); - fts_lexer->scanner = (fts_scan) fts_blexer; + fts_lexer->scanner = fts_blexer; /* FIXME: Debugging */ /* fts0bset_debug(1 , fts_lexer->yyscanner); */ } else { fts0tlex_init(&fts_lexer->yyscanner); fts0t_scan_bytes((char*) query, (int) query_len, fts_lexer->yyscanner); - fts_lexer->scanner = (fts_scan) fts_tlexer; + fts_lexer->scanner = fts_tlexer; } return(fts_lexer); @@ -258,7 +258,7 @@ fts_lexer_free( /*===========*/ fts_lexer_t* fts_lexer) { - if (fts_lexer->scanner == (fts_scan) fts_blexer) { + if (fts_lexer->scanner == fts_blexer) { fts0blex_destroy(fts_lexer->yyscanner); } else { fts0tlex_destroy(fts_lexer->yyscanner); @@ -275,9 +275,9 @@ fts_lexer( YYSTYPE* val, fts_lexer_t* fts_lexer) { - fts_scanner_alt func_ptr; + fts_scanner func_ptr; - func_ptr = (fts_scanner_alt) fts_lexer->scanner; + func_ptr = fts_lexer->scanner; return(func_ptr(val, fts_lexer->yyscanner)); } diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index 6a0496bedcd..5ae8e28974e 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -3920,6 +3920,7 @@ fts_query_can_optimize( } /** FTS Query entry point. +@param[in,out] trx transaction @param[in] index fts index to search @param[in] flags FTS search mode @param[in] query_str FTS query @@ -3928,6 +3929,7 @@ fts_query_can_optimize( @return DB_SUCCESS if successful otherwise error code */ dberr_t fts_query( + trx_t* trx, dict_index_t* index, uint flags, const byte* query_str, @@ -3940,7 +3942,7 @@ fts_query( ulint lc_query_str_len; ulint result_len; bool boolean_mode; - trx_t* query_trx; + trx_t* query_trx; /* FIXME: use provided trx */ CHARSET_INFO* charset; ulint start_time_ms; bool will_be_ignored = false; @@ -4055,6 +4057,7 @@ fts_query( /* Parse the input query string. */ if (fts_query_parse(&query, lc_query_str, result_len)) { fts_ast_node_t* ast = query.root; + ast->trx = trx; /* Optimize query to check if it's a single term */ fts_query_can_optimize(&query, flags); @@ -4068,6 +4071,11 @@ fts_query( query.error = fts_ast_visit( FTS_NONE, ast, fts_query_visitor, &query, &will_be_ignored); + if (query.error == DB_INTERRUPTED) { + error = DB_INTERRUPTED; + ut_free(lc_query_str); + goto func_exit; + } /* If query expansion is requested, extend the search with first search pass result */ @@ -4094,6 +4102,15 @@ fts_query( ut_zalloc_nokey(sizeof(**result))); } + if (trx_is_interrupted(trx)) { + error = DB_INTERRUPTED; + ut_free(lc_query_str); + if (*result) { + fts_query_free_result(*result); + } + goto func_exit; + } + ut_free(lc_query_str); if (fts_enable_diag_print && (*result)) { diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index eac904e5b24..146d1616347 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -658,7 +658,7 @@ rtr_adjust_upper_level( /* Create a memory heap where the data tuple is stored */ heap = mem_heap_create(1024); - memset(&cursor, 0, sizeof(cursor)); + cursor.init(); cursor.thr = sea_cur->thr; @@ -1367,7 +1367,7 @@ rtr_ins_enlarge_mbr( rtr_page_cal_mbr(index, block, &new_mbr, heap); /* Get father block. */ - memset(&cursor, 0, sizeof(cursor)); + cursor.init(); offsets = rtr_page_get_father_block( NULL, heap, index, block, mtr, btr_cur, &cursor); diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index 67b2feb7af6..b137a768830 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -1546,7 +1546,7 @@ rtr_copy_buf( will be copied. It is also undefined what will happen with the newly memcpy()ed mutex if the source mutex was acquired by (another) thread while it was copied. */ - memcpy(&matches->block.page, &block->page, sizeof(buf_page_t)); + new (&matches->block.page) buf_page_t(block->page); matches->block.frame = block->frame; matches->block.unzip_LRU = block->unzip_LRU; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2b7c700dd55..e2b61b627de 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5324,15 +5324,16 @@ ha_innobase::max_supported_key_length() const switch (srv_page_size) { case 4096: - return(768); + /* Hack: allow mysql.innodb_index_stats to be created. */ + /* FIXME: rewrite this API, and in sql_table.cc consider + that in index-organized tables (such as InnoDB), secondary + index records will be padded with the PRIMARY KEY, instead + of some short ROWID or record heap address. */ + return(1173); case 8192: return(1536); default: -#ifdef WITH_WSREP - return(3500); -#else return(3500); -#endif } } @@ -10071,8 +10072,7 @@ ha_innobase::ft_init_ext( const_cast<char*>(query)); // FIXME: support ft_init_ext_with_hints(), pass LIMIT - // FIXME: use trx - dberr_t error = fts_query(index, flags, q, query_len, &result); + dberr_t error = fts_query(trx, index, flags, q, query_len, &result); if (error != DB_SUCCESS) { my_error(convert_error_code_to_mysql(error, 0, NULL), MYF(0)); @@ -13266,6 +13266,36 @@ innobase_rename_table( row_mysql_lock_data_dictionary(trx); + dict_table_t* table = dict_table_open_on_name(norm_from, TRUE, FALSE, + DICT_ERR_IGNORE_NONE); + + /* Since DICT_BG_YIELD has sleep for 250 milliseconds, + Convert lock_wait_timeout unit from second to 250 milliseconds */ + long int lock_wait_timeout = thd_lock_wait_timeout(trx->mysql_thd) * 4; + if (table != NULL) { + for (dict_index_t* index = dict_table_get_first_index(table); + index != NULL; + index = dict_table_get_next_index(index)) { + + if (index->type & DICT_FTS) { + /* Found */ + while (index->index_fts_syncing + && !trx_is_interrupted(trx) + && (lock_wait_timeout--) > 0) { + DICT_BG_YIELD(trx); + } + } + } + dict_table_close(table, TRUE, FALSE); + } + + /* FTS sync is in progress. We shall timeout this operation */ + if (lock_wait_timeout < 0) { + error = DB_LOCK_WAIT_TIMEOUT; + row_mysql_unlock_data_dictionary(trx); + DBUG_RETURN(error); + } + error = row_rename_table_for_mysql(norm_from, norm_to, trx, TRUE); if (error != DB_SUCCESS) { @@ -13395,6 +13425,10 @@ ha_innobase::rename_table( my_error(ER_TABLE_EXISTS_ERROR, MYF(0), to); error = DB_ERROR; + } else if (error == DB_LOCK_WAIT_TIMEOUT) { + my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0), to); + + error = DB_LOCK_WAIT; } DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 3f251b2f6f6..a8cbee11c8e 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -9431,24 +9431,24 @@ ha_innobase::commit_inplace_alter_table( trx_t* trx = ctx0->trx; bool fail = false; - if (new_clustered) { - for (inplace_alter_handler_ctx** pctx = ctx_array; - *pctx; pctx++) { - ha_innobase_inplace_ctx* ctx - = static_cast<ha_innobase_inplace_ctx*>(*pctx); - DBUG_ASSERT(ctx->need_rebuild()); + /* Stop background FTS operations. */ + for (inplace_alter_handler_ctx** pctx = ctx_array; + *pctx; pctx++) { + ha_innobase_inplace_ctx* ctx + = static_cast<ha_innobase_inplace_ctx*>(*pctx); + + DBUG_ASSERT(new_clustered == ctx->need_rebuild()); + if (new_clustered) { if (ctx->old_table->fts) { ut_ad(!ctx->old_table->fts->add_wq); - fts_optimize_remove_table( - ctx->old_table); + fts_optimize_remove_table(ctx->old_table); } + } - if (ctx->new_table->fts) { - ut_ad(!ctx->new_table->fts->add_wq); - fts_optimize_remove_table( - ctx->new_table); - } + if (ctx->new_table->fts) { + ut_ad(!ctx->new_table->fts->add_wq); + fts_optimize_remove_table(ctx->new_table); } } @@ -9495,41 +9495,39 @@ ha_innobase::commit_inplace_alter_table( /* Make a concurrent Drop fts Index to wait until sync of that fts index is happening in the background */ - for (;;) { + for (int retry_count = 0;;) { bool retry = false; for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) { - int count =0; ha_innobase_inplace_ctx* ctx = static_cast<ha_innobase_inplace_ctx*>(*pctx); DBUG_ASSERT(new_clustered == ctx->need_rebuild()); if (dict_fts_index_syncing(ctx->old_table)) { - count++; - if (count == 100) { - fprintf(stderr, - "Drop index waiting for background sync" - "to finish\n"); - } retry = true; + break; } if (new_clustered && dict_fts_index_syncing(ctx->new_table)) { - count++; - if (count == 100) { - fprintf(stderr, - "Drop index waiting for background sync" - "to finish\n"); - } retry = true; + break; } } - if (!retry) { + if (!retry) { break; } + /* Print a message if waiting for a long time. */ + if (retry_count < 100) { + retry_count++; + } else { + ib::info() << "Drop index waiting for background sync" + " to finish"; + retry_count = 0; + } + DICT_BG_YIELD(trx); } @@ -9806,6 +9804,11 @@ foreign_fail: ut_a(fts_check_cached_index(ctx->old_table)); DBUG_INJECT_CRASH("ib_commit_inplace_crash_fail", crash_fail_inject_count++); + + /* Restart the FTS background operations. */ + if (ctx->old_table->fts) { + fts_optimize_add_table(ctx->old_table); + } } row_mysql_unlock_data_dictionary(trx); @@ -9889,8 +9892,6 @@ foreign_fail: (*pctx); DBUG_ASSERT(ctx->need_rebuild() == new_clustered); - bool add_fts = false; - /* Publish the created fulltext index, if any. Note that a fulltext index can be created without creating the clustered index, if there already exists @@ -9905,14 +9906,14 @@ foreign_fail: is left unset when a drop proceeds the add. */ DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS); fts_add_index(index, ctx->new_table); - add_fts = true; } } ut_d(dict_table_check_for_dup_indexes( ctx->new_table, CHECK_ALL_COMPLETE)); - if (add_fts) { + /* Start/Restart the FTS background operations. */ + if (ctx->new_table->fts) { fts_optimize_add_table(ctx->new_table); } diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 25dd9e9993d..f0df1bc9839 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -1359,12 +1359,14 @@ i_s_cmp_fill_low( page0zip.cc. */ table->field[1]->store(zip_stat->compressed, true); table->field[2]->store(zip_stat->compressed_ok, true); - table->field[3]->store(zip_stat->compressed_usec / 1000000, true); + table->field[3]->store(zip_stat->compressed_usec / 1000000, + true); table->field[4]->store(zip_stat->decompressed, true); - table->field[5]->store(zip_stat->decompressed_usec / 1000000, true); + table->field[5]->store(zip_stat->decompressed_usec / 1000000, + true); if (reset) { - memset(zip_stat, 0, sizeof *zip_stat); + new (zip_stat) page_zip_stat_t(); } if (schema_table_store_record(thd, table)) { diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index dc1f6dd82d8..f87370be70c 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -955,6 +955,26 @@ struct btr_cur_t { rtr_info_t* rtr_info; /*!< rtree search info */ btr_cur_t():thr(NULL), rtr_info(NULL) {} /* default values */ + /** Zero-initialize all fields */ + void init() + { + index = NULL; + memset(&page_cur, 0, sizeof page_cur); + purge_node = NULL; + left_block = NULL; + thr = NULL; + flag = btr_cur_method(0); + tree_height = 0; + up_match = 0; + up_bytes = 0; + low_match = 0; + low_bytes = 0; + n_fields = 0; + n_bytes = 0; + fold = 0; + path_arr = NULL; + rtr_info = NULL; + } }; /******************************************************//** diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index f478d3fa876..747ad676e33 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -538,6 +538,18 @@ struct btr_pcur_t{ /** old_rec_buf size if old_rec_buf is not NULL */ ulint buf_size; + btr_pcur_t() : + btr_cur(), latch_mode(0), old_stored(false), old_rec(NULL), + old_n_fields(0), rel_pos(btr_pcur_pos_t(0)), + block_when_stored(NULL), + modify_clock(0), withdraw_clock(0), + pos_state(BTR_PCUR_NOT_POSITIONED), + search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL), + old_rec_buf(NULL), buf_size(0) + { + btr_cur.init(); + } + /** Return the index of this persistent cursor */ dict_index_t* index() const { return(btr_cur.index); } }; diff --git a/storage/innobase/include/dict0defrag_bg.h b/storage/innobase/include/dict0defrag_bg.h index 8d77a461dc9..ddef139853c 100644 --- a/storage/innobase/include/dict0defrag_bg.h +++ b/storage/innobase/include/dict0defrag_bg.h @@ -33,6 +33,25 @@ Created 25/08/2016 Jan Lindström #include "os0event.h" #include "os0thread.h" + +/** Indices whose defrag stats need to be saved to persistent storage.*/ +struct defrag_pool_item_t { + table_id_t table_id; + index_id_t index_id; +}; + +/** Allocator type, used by std::vector */ +typedef ut_allocator<defrag_pool_item_t> + defrag_pool_allocator_t; + +/** The multitude of tables to be defragmented- an STL vector */ +typedef std::vector<defrag_pool_item_t, defrag_pool_allocator_t> + defrag_pool_t; + +/** Pool where we store information on which tables are to be processed +by background defragmentation. */ +extern defrag_pool_t defrag_pool; + /*****************************************************************//** Initialize the defrag pool, called once during thread initialization. */ void diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 66b64f96128..3dcf290a276 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1862,14 +1862,6 @@ const char* dict_tf_to_row_format_string( /*=========================*/ ulint table_flag); /*!< in: row format setting */ -/****************************************************************//** -Return maximum size of the node pointer record. -@return maximum size of the record in bytes */ -ulint -dict_index_node_ptr_max_size( -/*=========================*/ - const dict_index_t* index) /*!< in: index */ - MY_ATTRIBUTE((warn_unused_result)); /** encode number of columns and number of virtual columns in one 4 bytes value. We could do this because the number of columns in diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 8d7c9d47e9f..3e06def55b0 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -771,6 +771,9 @@ struct dict_field_t{ column if smaller than DICT_ANTELOPE_MAX_INDEX_COL_LEN */ + /** Zero-initialize all fields */ + dict_field_t() : col(NULL), name(NULL), prefix_len(0), fixed_len(0) {} + /** Check whether two index fields are equivalent. @param[in] old the other index field @return whether the index fields are equivalent */ diff --git a/storage/innobase/include/dict0stats.h b/storage/innobase/include/dict0stats.h index 5dd53c46d1b..407e0221110 100644 --- a/storage/innobase/include/dict0stats.h +++ b/storage/innobase/include/dict0stats.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2009, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2009, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -32,6 +32,9 @@ Created Jan 06, 2010 Vasil Dimov #include "dict0types.h" #include "trx0types.h" +#define TABLE_STATS_NAME "mysql/innodb_table_stats" +#define INDEX_STATS_NAME "mysql/innodb_index_stats" + enum dict_stats_upd_option_t { DICT_STATS_RECALC_PERSISTENT,/* (re) calculate the statistics using a precise and slow @@ -110,12 +113,21 @@ dict_stats_deinit( dict_table_t* table) /*!< in/out: table */ MY_ATTRIBUTE((nonnull)); +#ifdef WITH_WSREP +/** Update the table modification counter and if necessary, +schedule new estimates for table and index statistics to be calculated. +@param[in,out] table persistent or temporary table +@param[in] thd current session */ +void dict_stats_update_if_needed(dict_table_t* table, THD* thd) + MY_ATTRIBUTE((nonnull(1))); +#else /** Update the table modification counter and if necessary, schedule new estimates for table and index statistics to be calculated. @param[in,out] table persistent or temporary table */ -void -dict_stats_update_if_needed(dict_table_t* table) +void dict_stats_update_if_needed_func(dict_table_t* table) MY_ATTRIBUTE((nonnull)); +# define dict_stats_update_if_needed(t,thd) dict_stats_update_if_needed_func(t) +#endif /*********************************************************************//** Calculates new estimates for table and index statistics. The statistics diff --git a/storage/innobase/include/fts0ast.h b/storage/innobase/include/fts0ast.h index b5187ce2a41..2a2b25c36bd 100644 --- a/storage/innobase/include/fts0ast.h +++ b/storage/innobase/include/fts0ast.h @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, 2018, 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 @@ -296,6 +297,8 @@ struct fts_ast_node_t { fts_ast_node_t* next_alloc; /*!< For tracking allocations */ bool visited; /*!< whether this node is already processed */ + /** current transaction */ + const trx_t* trx; /* Used by plugin parser */ fts_ast_node_t* up_node; /*!< Direct up node */ bool go_up; /*!< Flag if go one level up */ diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index be2fe7e040b..068720c1947 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2016, 2017, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -561,6 +561,7 @@ fts_commit( MY_ATTRIBUTE((warn_unused_result)); /** FTS Query entry point. +@param[in,out] trx transaction @param[in] index fts index to search @param[in] flags FTS search mode @param[in] query_str FTS query @@ -569,6 +570,7 @@ fts_commit( @return DB_SUCCESS if successful otherwise error code */ dberr_t fts_query( + trx_t* trx, dict_index_t* index, uint flags, const byte* query_str, @@ -711,6 +713,12 @@ fts_drop_index_tables( dict_index_t* index) /*!< in: Index to drop */ MY_ATTRIBUTE((warn_unused_result)); +/** Add the table to add to the OPTIMIZER's list. +@param[in] table table to add */ +void +fts_optimize_add_table( + dict_table_t* table); + /******************************************************************//** Remove the table from the OPTIMIZER's list. We do wait for acknowledgement from the consumer of the message. */ diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h index aef6e816461..d045c9d3c72 100644 --- a/storage/innobase/include/fts0priv.h +++ b/storage/innobase/include/fts0priv.h @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 2018, 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 @@ -512,13 +512,6 @@ fts_get_table_id( MY_ATTRIBUTE((warn_unused_result)); /******************************************************************//** -Add the table to add to the OPTIMIZER's list. */ -void -fts_optimize_add_table( -/*===================*/ - dict_table_t* table); /*!< in: table to add */ - -/******************************************************************//** Construct the prefix name of an FTS table. @return own: table name, must be freed with ut_free() */ char* diff --git a/storage/innobase/include/row0ftsort.h b/storage/innobase/include/row0ftsort.h index 25204895f1a..3ae5d5bc175 100644 --- a/storage/innobase/include/row0ftsort.h +++ b/storage/innobase/include/row0ftsort.h @@ -122,6 +122,16 @@ struct fts_tokenize_ctx { dfield_t sort_field[FTS_NUM_FIELDS_SORT]; /*!< in: sort field */ fts_token_list_t fts_token_list; + + fts_tokenize_ctx() : + processed_len(0), init_pos(0), buf_used(0), + rows_added(), cached_stopword(NULL), sort_field(), + fts_token_list() + { + memset(rows_added, 0, sizeof rows_added); + memset(sort_field, 0, sizeof sort_field); + UT_LIST_INIT(fts_token_list, &row_fts_token_t::token_list); + } }; typedef struct fts_tokenize_ctx fts_tokenize_ctx_t; diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index ffa4967b9de..bf1d245a65e 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -41,7 +41,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 5 #define INNODB_VERSION_MINOR 7 -#define INNODB_VERSION_BUGFIX 22 +#define INNODB_VERSION_BUGFIX 23 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 4d93f2c449c..461dec3ee29 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1750,7 +1750,10 @@ lock_rec_enqueue_waiting( lock_prdt_set_prdt(lock, prdt); } - if (const trx_t* victim = + if ( +#ifdef UNIV_DEBUG + const trx_t* victim = +#endif DeadlockChecker::check_and_resolve(lock, trx)) { ut_ad(victim == trx); lock_reset_lock_and_trx_wait(lock); diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index c6da047e8c5..208fe356fbe 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -2496,30 +2496,15 @@ os_file_fsync_posix( os_thread_sleep(200000); break; - case EIO: - - ++failures; - ut_a(failures < 1000); - - if (!(failures % 100)) { - - ib::warn() - << "fsync(): " - << "An error occurred during " - << "synchronization," - << " retrying"; - } - - /* 0.2 sec */ - os_thread_sleep(200000); - break; - case EINTR: ++failures; ut_a(failures < 2000); break; + case EIO: + ib::error() << "fsync() returned EIO, aborting"; + /* fall through */ default: ut_error; break; @@ -3325,7 +3310,8 @@ os_file_get_status_posix( { int ret = stat(path, statinfo); - if (ret && (errno == ENOENT || errno == ENOTDIR)) { + if (ret && (errno == ENOENT || errno == ENOTDIR + || errno == ENAMETOOLONG)) { /* file does not exist */ return(DB_NOT_FOUND); @@ -4665,7 +4651,8 @@ os_file_get_status_win32( { int ret = _stat64(path, statinfo); - if (ret && (errno == ENOENT || errno == ENOTDIR)) { + if (ret && (errno == ENOENT || errno == ENOTDIR + || errno == ENAMETOOLONG)) { /* file does not exist */ return(DB_NOT_FOUND); diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index 4341886d775..a351a1ae01b 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -805,7 +805,6 @@ DECLARE_THREAD(fts_parallel_tokenization)( merge_file = psort_info->merge_file; blob_heap = mem_heap_create(512); memset(&doc, 0, sizeof(doc)); - memset(&t_ctx, 0, sizeof(t_ctx)); memset(mycount, 0, FTS_NUM_AUX_INDEX * sizeof(int)); doc.charset = fts_index_get_charset( diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 0357804f617..aab445cb197 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2012, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2015, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -113,19 +113,19 @@ struct row_index_t { struct row_import { row_import() UNIV_NOTHROW : - m_table(), - m_version(), - m_hostname(), - m_table_name(), - m_autoinc(), + m_table(NULL), + m_version(0), + m_hostname(NULL), + m_table_name(NULL), + m_autoinc(0), m_page_size(0, 0, false), - m_flags(), - m_n_cols(), - m_cols(), - m_col_names(), - m_n_indexes(), - m_indexes(), - m_missing(true) {} + m_flags(0), + m_n_cols(0), + m_cols(NULL), + m_col_names(NULL), + m_n_indexes(0), + m_indexes(NULL), + m_missing(true) { } ~row_import() UNIV_NOTHROW; @@ -1227,17 +1227,63 @@ row_import::match_schema( { /* Do some simple checks. */ - if ((m_table->flags ^ m_flags) & ~DICT_TF_MASK_DATA_DIR) { + if (ulint mismatch = (m_table->flags ^ m_flags) + & ~DICT_TF_MASK_DATA_DIR) { + const char* msg; + if (mismatch & DICT_TF_MASK_ZIP_SSIZE) { + if ((m_table->flags & DICT_TF_MASK_ZIP_SSIZE) + && (m_flags & DICT_TF_MASK_ZIP_SSIZE)) { + switch (m_flags & DICT_TF_MASK_ZIP_SSIZE) { + case 0U << DICT_TF_POS_ZIP_SSIZE: + goto uncompressed; + case 1U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=1"; + break; + case 2U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=2"; + break; + case 3U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=4"; + break; + case 4U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=8"; + break; + case 5U << DICT_TF_POS_ZIP_SSIZE: + msg = "ROW_FORMAT=COMPRESSED" + " KEY_BLOCK_SIZE=16"; + break; + default: + msg = "strange KEY_BLOCK_SIZE"; + } + } else if (m_flags & DICT_TF_MASK_ZIP_SSIZE) { + msg = "ROW_FORMAT=COMPRESSED"; + } else { + goto uncompressed; + } + } else { +uncompressed: + msg = (m_flags & DICT_TF_MASK_ATOMIC_BLOBS) + ? "ROW_FORMAT=DYNAMIC" + : (m_flags & DICT_TF_MASK_COMPACT) + ? "ROW_FORMAT=COMPACT" + : "ROW_FORMAT=REDUNDANT"; + } + ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, "Table flags don't match, server table has 0x%x" - " and the meta-data file has 0x" ULINTPFx, - m_table->flags, m_flags); + " and the meta-data file has 0x" ULINTPFx ";" + " .cfg file uses %s", + m_table->flags, m_flags, msg); return(DB_ERROR); } else if (m_table->n_cols != m_n_cols) { ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH, - "Number of columns don't match, table has %u" - " columns but the tablespace meta-data file has " + "Number of columns don't match, table has %u " + "columns but the tablespace meta-data file has " ULINTPF " columns", m_table->n_cols, m_n_cols); @@ -1686,7 +1732,6 @@ PageConverter::update_records( while (!m_rec_iter.end()) { rec_t* rec = m_rec_iter.current(); - ibool deleted = rec_get_deleted_flag(rec, comp); /* For the clustered index we have to adjust the BLOB @@ -2359,8 +2404,6 @@ row_import_cfg_read_index_fields( dict_field_t* field = index->m_fields; - memset(field, 0x0, sizeof(*field) * n_fields); - for (ulint i = 0; i < n_fields; ++i, ++field) { byte* ptr = row; @@ -2378,6 +2421,8 @@ row_import_cfg_read_index_fields( return(DB_IO_ERROR); } + new (field) dict_field_t(); + field->prefix_len = mach_read_from_4(ptr); ptr += sizeof(ib_uint32_t); @@ -3787,8 +3832,6 @@ row_import_for_mysql( row_import cfg; - memset(&cfg, 0x0, sizeof(cfg)); - err = row_import_read_cfg(table, trx->mysql_thd, cfg); /* Check if the table column definitions match the contents diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 37ae828d09d..c6ac98f1082 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1660,7 +1660,8 @@ row_ins_check_foreign_constraint( if (check_table == NULL || !check_table->is_readable() - || check_index == NULL) { + || check_index == NULL + || check_table->space->is_being_truncated) { if (!srv_read_only_mode && check_ref) { FILE* ef = dict_foreign_err_file; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 49ac2638ef8..a3c3d0eaaa6 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -72,6 +72,13 @@ Created 9/17/2000 Heikki Tuuri #include <deque> #include <vector> +#ifdef WITH_WSREP +#include "mysql/service_wsrep.h" +#include "wsrep.h" +#include "log.h" +#include "wsrep_mysqld.h" +#endif + /** Provide optional 4.x backwards compatibility for 5.0 and above */ ibool row_rollback_on_timeout = FALSE; @@ -1568,7 +1575,7 @@ error_exit: memcpy(prebuilt->row_id, node->sys_buf, DATA_ROW_ID_LEN); } - dict_stats_update_if_needed(table); + dict_stats_update_if_needed(table, trx->mysql_thd); trx->op_info = ""; if (blob_heap != NULL) { @@ -1952,7 +1959,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt) } if (update_statistics) { - dict_stats_update_if_needed(prebuilt->table); + dict_stats_update_if_needed(prebuilt->table, trx->mysql_thd); } else { /* Always update the table modification counter. */ prebuilt->table->stat_modified_counter++; @@ -2195,7 +2202,7 @@ static dberr_t row_update_vers_insert(que_thr_t* thr, upd_node_t* node) case DB_SUCCESS: srv_stats.n_rows_inserted.inc( static_cast<size_t>(trx->id)); - dict_stats_update_if_needed(table); + dict_stats_update_if_needed(table, trx->mysql_thd); goto exit; } } @@ -2288,7 +2295,8 @@ row_update_cascade_for_mysql( } if (stats) { - dict_stats_update_if_needed(node->table); + dict_stats_update_if_needed(node->table, + trx->mysql_thd); } else { /* Always update the table modification counter. */ diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 79ce3057cd7..e2bbb5a3d5e 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -1156,9 +1156,9 @@ row_purge_record_func( /*==================*/ purge_node_t* node, /*!< in: row purge node */ trx_undo_rec_t* undo_rec, /*!< in: record to purge */ -#ifdef UNIV_DEBUG +#if defined UNIV_DEBUG || defined WITH_WSREP const que_thr_t*thr, /*!< in: query thread */ -#endif /* UNIV_DEBUG */ +#endif /* UNIV_DEBUG || WITH_WSREP */ bool updated_extern) /*!< in: whether external columns were updated */ { @@ -1179,7 +1179,9 @@ row_purge_record_func( if (purged) { if (node->table->stat_initialized && srv_stats_include_delete_marked) { - dict_stats_update_if_needed(node->table); + dict_stats_update_if_needed( + node->table, + thr->graph->trx->mysql_thd); } MONITOR_INC(MONITOR_N_DEL_ROW_PURGE); } @@ -1214,13 +1216,13 @@ row_purge_record_func( return(purged); } -#ifdef UNIV_DEBUG +#if defined UNIV_DEBUG || defined WITH_WSREP # define row_purge_record(node,undo_rec,thr,updated_extern) \ row_purge_record_func(node,undo_rec,thr,updated_extern) -#else /* UNIV_DEBUG */ +#else /* UNIV_DEBUG || WITH_WSREP */ # define row_purge_record(node,undo_rec,thr,updated_extern) \ row_purge_record_func(node,undo_rec,updated_extern) -#endif /* UNIV_DEBUG */ +#endif /* UNIV_DEBUG || WITH_WSREP */ /***********************************************************//** Fetches an undo log record and does the purge for the recorded operation. diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc index abd037e4a49..65170a10f57 100644 --- a/storage/innobase/row/row0trunc.cc +++ b/storage/innobase/row/row0trunc.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2013, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2013, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under @@ -1181,6 +1181,11 @@ row_truncate_complete( { bool is_file_per_table = dict_table_is_file_per_table(table); + /* Add the table back to FTS optimize background thread. */ + if (table->fts) { + fts_optimize_add_table(table); + } + row_mysql_unlock_data_dictionary(trx); DEBUG_SYNC_C("ib_trunc_table_trunc_completing"); @@ -1507,6 +1512,9 @@ row_truncate_update_system_tables( /* Reset the Doc ID in cache to 0 */ if (has_internal_doc_id && table->fts->cache != NULL) { + DBUG_EXECUTE_IF("ib_trunc_sleep_before_fts_cache_clear", + os_thread_sleep(10000000);); + table->fts->fts_status |= TABLE_DICT_LOCKED; fts_update_next_doc_id(trx, table, NULL, 0); fts_cache_clear(table->fts->cache); @@ -1754,6 +1762,10 @@ row_truncate_table_for_mysql( } if (!table->is_temporary()) { + if (table->fts) { + fts_optimize_remove_table(table); + } + trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); } diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index cbcb4eb8d1d..2067e957f3c 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -273,8 +273,6 @@ row_undo_ins_remove_sec_low( enum row_search_result search_result; const bool modify_leaf = mode == BTR_MODIFY_LEAF; - memset(&pcur, 0, sizeof(pcur)); - row_mtr_start(&mtr, index, !modify_leaf); if (modify_leaf) { @@ -631,7 +629,8 @@ row_undo_ins( already be holding dict_sys->mutex, which would be acquired when updating statistics. */ if (!dict_locked) { - dict_stats_update_if_needed(node->table); + dict_stats_update_if_needed( + node->table, node->trx->mysql_thd); } } } diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 64d771d7d94..90bce6c8be6 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -1351,7 +1351,8 @@ rollback_clust: already be holding dict_sys->mutex, which would be acquired when updating statistics. */ if (update_statistics && !dict_locked) { - dict_stats_update_if_needed(node->table); + dict_stats_update_if_needed( + node->table, node->trx->mysql_thd); } else { node->table->stat_modified_counter++; } diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc index ab4814f3177..d5b0537c095 100644 --- a/storage/innobase/sync/sync0rw.cc +++ b/storage/innobase/sync/sync0rw.cc @@ -1042,86 +1042,52 @@ rw_lock_own( return(false); } -/** For collecting the debug information for a thread's rw-lock */ -typedef std::vector<rw_lock_debug_t*> Infos; - -/** Get the thread debug info -@param[in] infos The rw-lock mode owned by the threads -@param[in] lock rw-lock to check -@return the thread debug info or NULL if not found */ -void -rw_lock_get_debug_info(const rw_lock_t* lock, Infos* infos) -{ - rw_lock_debug_t* info = NULL; - - ut_ad(rw_lock_validate(lock)); - - rw_lock_debug_mutex_enter(); - - for (info = UT_LIST_GET_FIRST(lock->debug_list); - info != NULL; - info = UT_LIST_GET_NEXT(list, info)) { - - if (os_thread_eq(info->thread_id, os_thread_get_curr_id())) { - - infos->push_back(info); - } - } - - rw_lock_debug_mutex_exit(); -} - /** Checks if the thread has locked the rw-lock in the specified mode, with the pass value == 0. @param[in] lock rw-lock @param[in] flags specify lock types with OR of the rw_lock_flag_t values @return true if locked */ -bool -rw_lock_own_flagged( - const rw_lock_t* lock, - rw_lock_flags_t flags) +bool rw_lock_own_flagged(const rw_lock_t* lock, rw_lock_flags_t flags) { - Infos infos; - - rw_lock_get_debug_info(lock, &infos); - - Infos::const_iterator end = infos.end(); - - for (Infos::const_iterator it = infos.begin(); it != end; ++it) { + ut_ad(rw_lock_validate(lock)); - const rw_lock_debug_t* info = *it; + rw_lock_debug_mutex_enter(); - if (info->pass) { + for (rw_lock_debug_t* info = UT_LIST_GET_FIRST(lock->debug_list); + info != NULL; + info = UT_LIST_GET_NEXT(list, info)) { + if (!os_thread_eq(info->thread_id, os_thread_get_curr_id()) + || info->pass) { continue; } - ut_ad(os_thread_eq(info->thread_id, os_thread_get_curr_id())); - switch (info->lock_type) { case RW_LOCK_S: - - if (flags & RW_LOCK_FLAG_S) { - return(true); + if (!(flags & RW_LOCK_FLAG_S)) { + continue; } break; case RW_LOCK_X: - - if (flags & RW_LOCK_FLAG_X) { - return(true); + if (!(flags & RW_LOCK_FLAG_X)) { + continue; } break; case RW_LOCK_SX: - - if (flags & RW_LOCK_FLAG_SX) { - return(true); + if (!(flags & RW_LOCK_FLAG_SX)) { + continue; } + break; } + + rw_lock_debug_mutex_exit(); + return true; } - return(false); + rw_lock_debug_mutex_exit(); + return false; } /***************************************************************//** @@ -1222,28 +1188,31 @@ rw_lock_t::locked_from() const the same thread can call X lock recursively. */ std::ostringstream msg; - Infos infos; + bool written = false; - rw_lock_get_debug_info(this, &infos); + ut_ad(rw_lock_validate(this)); - ulint i = 0; - Infos::const_iterator end = infos.end(); - - for (Infos::const_iterator it = infos.begin(); it != end; ++it, ++i) { - - const rw_lock_debug_t* info = *it; + rw_lock_debug_mutex_enter(); - ut_ad(os_thread_eq(info->thread_id, os_thread_get_curr_id())); + for (rw_lock_debug_t* info = UT_LIST_GET_FIRST(debug_list); + info != NULL; + info = UT_LIST_GET_NEXT(list, info)) { + if (!os_thread_eq(info->thread_id, os_thread_get_curr_id())) { + continue; + } - if (i > 0) { + if (written) { msg << ", "; } + written = true; + msg << info->file_name << ":" << info->line; } - return(msg.str()); + rw_lock_debug_mutex_exit(); + return(msg.str()); } /** Print the rw-lock information. diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 81ad85dca7d..0e56af81ed4 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -545,9 +545,7 @@ trx_rseg_array_init() *trx_sys.recovered_binlog_filename = '\0'; trx_sys.recovered_binlog_offset = 0; #ifdef WITH_WSREP - memset(&trx_sys.recovered_wsrep_xid, 0, - sizeof trx_sys.recovered_wsrep_xid); - trx_sys.recovered_wsrep_xid.formatID = -1; + trx_sys.recovered_wsrep_xid.null(); #endif for (ulint rseg_id = 0; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) { diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index c13ccdf53ed..5b3e4f04bd5 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -955,8 +955,7 @@ trx_start_low( } #ifdef WITH_WSREP - memset(trx->xid, 0, sizeof(xid_t)); - trx->xid->formatID = -1; + trx->xid->null(); #endif /* WITH_WSREP */ /* The initial value for trx->no: TRX_ID_MAX is used in |