diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-29 13:38:38 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-29 13:38:38 +0200 |
commit | 7b2bb67113bdda470955e3d4d72be0f2c0b38902 (patch) | |
tree | 9f9f34da1a4e48c243c56ff161987074ef907cbb /storage/innobase | |
parent | 27b762e23d8305bbc65dc61d283fe192e2dbd00a (diff) | |
parent | 1e778a3b5624f97fdf44a15fd6cee3d615891cff (diff) | |
download | mariadb-git-7b2bb67113bdda470955e3d4d72be0f2c0b38902.tar.gz |
Merge 10.3 into 10.4
Diffstat (limited to 'storage/innobase')
38 files changed, 595 insertions, 413 deletions
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index cbd280af223..a1c54d10776 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -28,6 +28,7 @@ SET(INNOBASE_SOURCES btr/btr0scrub.cc btr/btr0sea.cc btr/btr0defragment.cc + buf/buf0block_hint.cc buf/buf0buddy.cc buf/buf0buf.cc buf/buf0dblwr.cc diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 04aaccec84e..8ee7d167805 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -283,7 +283,7 @@ the index. ulint btr_height_get( /*===========*/ - dict_index_t* index, /*!< in: index tree */ + const dict_index_t* index, /*!< in: index tree */ mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint height=0; @@ -602,7 +602,7 @@ Gets the number of pages in a B-tree. ulint btr_get_size( /*=========*/ - dict_index_t* index, /*!< in: index */ + const dict_index_t* index, /*!< in: index */ ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ mtr_t* mtr) /*!< in/out: mini-transaction where index is s-latched */ diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index d998463ecf4..51c91c5b037 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -699,6 +699,8 @@ PageBulk::latch() m_index->set_modified(m_mtr); } + ut_ad(m_block->page.buf_fix_count); + /* In case the block is S-latched by page_cleaner. */ if (!buf_page_optimistic_get(RW_X_LATCH, m_block, m_modify_clock, __FILE__, __LINE__, &m_mtr)) { @@ -717,6 +719,8 @@ PageBulk::latch() buf_block_buf_fix_dec(m_block); + ut_ad(m_block->page.buf_fix_count); + ut_ad(m_cur_rec > m_page && m_cur_rec < m_heap_top); return (m_err); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 0cd65ad0a4c..59c6d06d5af 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -776,6 +776,8 @@ btr_cur_optimistic_latch_leaves( ulint mode; ulint left_page_no; ulint curr_page_no; + ut_ad(block->page.buf_fix_count); + ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); switch (*latch_mode) { case BTR_SEARCH_LEAF: @@ -787,20 +789,10 @@ btr_cur_optimistic_latch_leaves( mode = *latch_mode == BTR_SEARCH_PREV ? RW_S_LATCH : RW_X_LATCH; - buf_page_mutex_enter(block); - if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { - buf_page_mutex_exit(block); - return(false); - } - /* pin the block not to be relocated */ - buf_block_buf_fix_inc(block, file, line); - buf_page_mutex_exit(block); - rw_lock_s_lock(&block->lock); if (block->modify_clock != modify_clock) { rw_lock_s_unlock(&block->lock); - - goto unpin_failed; + return false; } curr_page_no = block->page.id.page_no(); @@ -826,7 +818,7 @@ btr_cur_optimistic_latch_leaves( /* release the left block */ btr_leaf_page_release( cursor->left_block, mode, mtr); - goto unpin_failed; + return false; } } else { cursor->left_block = NULL; @@ -836,23 +828,28 @@ btr_cur_optimistic_latch_leaves( file, line, mtr)) { if (btr_page_get_prev(buf_block_get_frame(block)) == left_page_no) { - buf_block_buf_fix_dec(block); + /* block was already buffer-fixed while + entering the function and + buf_page_optimistic_get() buffer-fixes + it again. */ + ut_ad(2 <= block->page.buf_fix_count); *latch_mode = mode; return(true); } else { - /* release the block */ + /* release the block and decrement of + buf_fix_count which was incremented + in buf_page_optimistic_get() */ btr_leaf_page_release(block, mode, mtr); } } + ut_ad(block->page.buf_fix_count); /* release the left block */ if (cursor->left_block != NULL) { btr_leaf_page_release(cursor->left_block, mode, mtr); } -unpin_failed: - /* unpin the block */ - buf_block_buf_fix_dec(block); + return(false); default: @@ -1416,12 +1413,7 @@ btr_cur_search_to_nth_level_func( guess = NULL; #else info = btr_search_get_info(index); - - if (!buf_pool_is_obsolete(info->withdraw_clock)) { - guess = info->root_guess; - } else { - guess = NULL; - } + guess = info->root_guess; #ifdef BTR_CUR_HASH_ADAPT @@ -1851,10 +1843,7 @@ retry_page_get: } #ifdef BTR_CUR_ADAPT - if (block != guess) { - info->root_guess = block; - info->withdraw_clock = buf_withdraw_clock; - } + info->root_guess = block; #endif } @@ -6847,21 +6836,19 @@ btr_record_not_null_field_in_rec( } } -/*******************************************************************//** -Estimates the number of different key values in a given index, for +/** Estimates the number of different key values in a given index, for each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index). The estimates are stored in the array index->stat_n_diff_key_vals[] (indexed 0..n_uniq-1) and the number of pages that were sampled is saved in -index->stat_n_sample_sizes[]. +result.n_sample_sizes[]. If innodb_stats_method is nulls_ignored, we also record the number of non-null values for each prefix and stored the estimates in -array index->stat_n_non_null_key_vals. -@return true if the index is available and we get the estimated numbers, -false if the index is unavailable. */ -bool -btr_estimate_number_of_different_key_vals( -/*======================================*/ - dict_index_t* index) /*!< in: index */ +array result.n_non_null_key_vals. +@param[in] index index +@return vector with statistics information +empty vector if the index is unavailable. */ +std::vector<index_field_stats_t> +btr_estimate_number_of_different_key_vals(dict_index_t* index) { btr_cur_t cursor; page_t* page; @@ -6881,11 +6868,11 @@ btr_estimate_number_of_different_key_vals( rec_offs* offsets_rec = NULL; rec_offs* offsets_next_rec = NULL; + std::vector<index_field_stats_t> result; + /* For spatial index, there is no such stats can be fetched. */ - if (dict_index_is_spatial(index)) { - return(false); - } + ut_ad(!dict_index_is_spatial(index)); n_cols = dict_index_get_n_unique(index); @@ -6994,7 +6981,7 @@ btr_estimate_number_of_different_key_vals( mtr_commit(&mtr); mem_heap_free(heap); - return(false); + return result; } /* Count the number of different key values for each prefix of @@ -7100,8 +7087,12 @@ exit_loop: also the pages used for external storage of fields (those pages are included in index->stat_n_leaf_pages) */ + result.reserve(n_cols); + for (j = 0; j < n_cols; j++) { - index->stat_n_diff_key_vals[j] + index_field_stats_t stat; + + stat.n_diff_key_vals = BTR_TABLE_STATS_FROM_SAMPLE( n_diff[j], index, n_sample_pages, total_external_size, not_empty_flag); @@ -7122,25 +7113,23 @@ exit_loop: add_on = n_sample_pages; } - index->stat_n_diff_key_vals[j] += add_on; + stat.n_diff_key_vals += add_on; - index->stat_n_sample_sizes[j] = n_sample_pages; + stat.n_sample_sizes = n_sample_pages; - /* Update the stat_n_non_null_key_vals[] with our - sampled result. stat_n_non_null_key_vals[] is created - and initialized to zero in dict_index_add_to_cache(), - along with stat_n_diff_key_vals[] array */ if (n_not_null != NULL) { - index->stat_n_non_null_key_vals[j] = + stat.n_non_null_key_vals = BTR_TABLE_STATS_FROM_SAMPLE( n_not_null[j], index, n_sample_pages, total_external_size, not_empty_flag); } + + result.push_back(stat); } mem_heap_free(heap); - return(true); + return result; } /*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/ diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 37444ee974d..9c5216dc015 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -198,11 +198,10 @@ before_first: cursor->old_n_fields, &cursor->old_rec_buf, &cursor->buf_size); - cursor->block_when_stored = block; + cursor->block_when_stored.store(block); /* Function try to check if block is S/X latch. */ cursor->modify_clock = buf_block_get_modify_clock(block); - cursor->withdraw_clock = buf_withdraw_clock; } /**************************************************************//** @@ -232,6 +231,26 @@ btr_pcur_copy_stored_position( pcur_receive->old_n_fields = pcur_donate->old_n_fields; } +/** Structure acts as functor to do the latching of leaf pages. +It returns true if latching of leaf pages succeeded and false +otherwise. */ +struct optimistic_latch_leaves +{ + btr_pcur_t *const cursor; + ulint *latch_mode; + mtr_t *const mtr; + + optimistic_latch_leaves(btr_pcur_t *cursor, ulint *latch_mode, mtr_t *mtr) + :cursor(cursor), latch_mode(latch_mode), mtr(mtr) {} + + bool operator() (buf_block_t *hint) const + { + return hint && btr_cur_optimistic_latch_leaves( + hint, cursor->modify_clock, latch_mode, + btr_pcur_get_btr_cur(cursor), __FILE__, __LINE__, mtr); + } +}; + /**************************************************************//** Restores the stored position of a persistent cursor bufferfixing the page and obtaining the specified latches. If the cursor position was saved when the @@ -294,7 +313,7 @@ btr_pcur_restore_position_func( cursor->latch_mode = BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode); cursor->pos_state = BTR_PCUR_IS_POSITIONED; - cursor->block_when_stored = btr_pcur_get_block(cursor); + cursor->block_when_stored.clear(); return(FALSE); } @@ -309,12 +328,9 @@ btr_pcur_restore_position_func( case BTR_MODIFY_PREV: /* Try optimistic restoration. */ - if (!buf_pool_is_obsolete(cursor->withdraw_clock) - && btr_cur_optimistic_latch_leaves( - cursor->block_when_stored, cursor->modify_clock, - &latch_mode, btr_pcur_get_btr_cur(cursor), - file, line, mtr)) { - + if (cursor->block_when_stored.run_with_hint( + optimistic_latch_leaves(cursor, &latch_mode, + mtr))) { cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->latch_mode = latch_mode; @@ -412,11 +428,10 @@ btr_pcur_restore_position_func( since the cursor can now be on a different page! But we can retain the value of old_rec */ - cursor->block_when_stored = btr_pcur_get_block(cursor); + cursor->block_when_stored.store(btr_pcur_get_block(cursor)); cursor->modify_clock = buf_block_get_modify_clock( - cursor->block_when_stored); + cursor->block_when_stored.block()); cursor->old_stored = true; - cursor->withdraw_clock = buf_withdraw_clock; mem_heap_free(heap); diff --git a/storage/innobase/buf/buf0block_hint.cc b/storage/innobase/buf/buf0block_hint.cc new file mode 100644 index 00000000000..9f974e8304d --- /dev/null +++ b/storage/innobase/buf/buf0block_hint.cc @@ -0,0 +1,78 @@ +/***************************************************************************** + +Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2020, MariaDB Corporation. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License, version 2.0, as published by the +Free Software Foundation. + +This program is also distributed with certain software (including but not +limited to OpenSSL) that is licensed under separate terms, as designated in a +particular file or component or in included license documentation. The authors +of MySQL hereby grant you an additional permission to link the program and +your derivative works with the separately licensed software that they have +included with MySQL. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, +for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*****************************************************************************/ + +#include "buf0block_hint.h" +namespace buf { + +void Block_hint::buffer_fix_block_if_still_valid() +{ + /* We need to check if m_block points to one of chunks. For this to be + meaningful we need to prevent freeing memory while we check, and until we + buffer-fix the block. For this purpose it is enough to latch any of the many + latches taken by buf_resize(). + However, for buffer-fixing to be meaningful, the block has to contain a page + (as opposed to being already empty, which might mean that buf_pool_resize() + can proceed and free it once we free the s-latch), so we confirm that the + block contains a page. However, it is not sufficient to check that this is + just any page, because just after we check it could get freed, unless we + have a latch which prevents this. This is tricky because page_hash latches + are sharded by page_id and we don't know the page_id until we look into the + block. To solve this chicken-and-egg problem somewhat, we latch the shard + for the m_page_id and compare block->page.id to it - so if is equal then we + can be reasonably sure that we have the correct latch. + There is still a theoretical problem here, where other threads might try + to modify the m_block->page.id while we are comparing it, but the chance of + accidentally causing the old space_id == m_page_id.m_space and the new + page_no == m_page_id.m_page_no is minimal as compilers emit a single 8-byte + comparison instruction to compare both at the same time atomically, and f() + will probably double-check the block->page.id again, anyway. + Finally, assuming that we have correct hash bucket latched, we should check if + the state of the block is BUF_BLOCK_FILE_PAGE before buffer-fixing the block, + as otherwise we risk buffer-fixing and operating on a block, which is already + meant to be freed. In particular, buf_LRU_free_page() first calls + buf_LRU_block_remove_hashed() under hash bucket latch protection to change the + state to BUF_BLOCK_REMOVE_HASH and then releases the latch. Later it calls + buf_LRU_block_free_hashed_page() without any latch to change the state to + BUF_BLOCK_MEMORY and reset the page's id, which means buf_resize() can free it + regardless of our buffer-fixing. */ + if (m_block) + { + const buf_pool_t *const buf_pool= buf_pool_get(m_page_id); + rw_lock_t *latch= buf_page_hash_lock_get(buf_pool, m_page_id); + rw_lock_s_lock(latch); + /* If not own buf_pool_mutex, page_hash can be changed. */ + latch= buf_page_hash_lock_s_confirm(latch, buf_pool, m_page_id); + if (buf_pool->is_block_field(m_block) && + m_page_id == m_block->page.id && + buf_block_get_state(m_block) == BUF_BLOCK_FILE_PAGE) + buf_block_buf_fix_inc(m_block, __FILE__, __LINE__); + else + clear(); + rw_lock_s_unlock(latch); + } +} +} // namespace buf diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index b13ac2ef2ac..6095f71f839 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -342,14 +342,6 @@ buf_pool_t* buf_pool_ptr; /** true when resizing buffer pool is in the critical path. */ volatile bool buf_pool_resizing; -/** true when withdrawing buffer pool pages might cause page relocation */ -volatile bool buf_pool_withdrawing; - -/** the clock is incremented every time a pointer to a page may become obsolete; -if the withdrwa clock has not changed, the pointer is still valid in buffer -pool. if changed, the pointer might not be in buffer pool any more. */ -volatile ulint buf_withdraw_clock; - /** Map of buffer pool chunks by its first frame address This is newly made by initialization of buffer pool and buf_resize_thread. Currently, no need mutex protection for update. */ @@ -2090,8 +2082,6 @@ buf_pool_init( NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE; buf_pool_resizing = false; - buf_pool_withdrawing = false; - buf_withdraw_clock = 0; buf_pool_ptr = (buf_pool_t*) ut_zalloc_nokey( n_instances * sizeof *buf_pool_ptr); @@ -2151,7 +2141,6 @@ buf_page_realloc( { buf_block_t* new_block; - ut_ad(buf_pool_withdrawing); ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); @@ -2573,9 +2562,6 @@ buf_pool_withdraw_blocks( ib::info() << "buffer pool " << i << " : withdrawn target " << UT_LIST_GET_LEN(buf_pool->withdraw) << " blocks."; - /* retry is not needed */ - ++buf_withdraw_clock; - return(false); } @@ -2672,7 +2658,6 @@ buf_pool_resize() NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE; ut_ad(!buf_pool_resizing); - ut_ad(!buf_pool_withdrawing); ut_ad(srv_buf_pool_chunk_unit > 0); new_instance_size = srv_buf_pool_size / srv_buf_pool_instances; @@ -2740,7 +2725,6 @@ buf_pool_resize() ut_ad(buf_pool->withdraw_target == 0); buf_pool->withdraw_target = withdraw_target; - buf_pool_withdrawing = true; } } @@ -2765,7 +2749,6 @@ withdraw_retry: if (srv_shutdown_state != SRV_SHUTDOWN_NONE) { /* abort to resize for shutdown. */ - buf_pool_withdrawing = false; return; } @@ -2827,7 +2810,6 @@ withdraw_retry: goto withdraw_retry; } - buf_pool_withdrawing = false; buf_resize_status("Latching whole of buffer pool."); @@ -4011,37 +3993,6 @@ buf_block_from_ahi(const byte* ptr) /********************************************************************//** Find out if a pointer belongs to a buf_block_t. It can be a pointer to -the buf_block_t itself or a member of it. This functions checks one of -the buffer pool instances. -@return TRUE if ptr belongs to a buf_block_t struct */ -static -ibool -buf_pointer_is_block_field_instance( -/*================================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - const void* ptr) /*!< in: pointer not dereferenced */ -{ - const buf_chunk_t* chunk = buf_pool->chunks; - const buf_chunk_t* const echunk = chunk + ut_min( - buf_pool->n_chunks, buf_pool->n_chunks_new); - - /* TODO: protect buf_pool->chunks with a mutex (the older pointer will - currently remain while during buf_pool_resize()) */ - while (chunk < echunk) { - if (ptr >= (void*) chunk->blocks - && ptr < (void*) (chunk->blocks + chunk->size)) { - - return(TRUE); - } - - chunk++; - } - - return(FALSE); -} - -/********************************************************************//** -Find out if a pointer belongs to a buf_block_t. It can be a pointer to the buf_block_t itself or a member of it @return TRUE if ptr belongs to a buf_block_t struct */ ibool @@ -4052,11 +4003,7 @@ buf_pointer_is_block_field( ulint i; for (i = 0; i < srv_buf_pool_instances; i++) { - ibool found; - - found = buf_pointer_is_block_field_instance( - buf_pool_from_array(i), ptr); - if (found) { + if (buf_pool_from_array(i)->is_block_field(ptr)) { return(TRUE); } } @@ -4064,25 +4011,6 @@ buf_pointer_is_block_field( return(FALSE); } -/********************************************************************//** -Find out if a buffer block was created by buf_chunk_init(). -@return TRUE if "block" has been added to buf_pool->free by buf_chunk_init() */ -static -ibool -buf_block_is_uncompressed( -/*======================*/ - buf_pool_t* buf_pool, /*!< in: buffer pool instance */ - const buf_block_t* block) /*!< in: pointer to block, - not dereferenced */ -{ - if ((((ulint) block) % sizeof *block) != 0) { - /* The pointer should be aligned. */ - return(FALSE); - } - - return(buf_pointer_is_block_field_instance(buf_pool, (void*) block)); -} - #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG /********************************************************************//** Return true if probe is enabled. @@ -4322,7 +4250,7 @@ loop: has been allocated by buf_page_alloc_descriptor(), it may have been freed by buf_relocate(). */ - if (!buf_block_is_uncompressed(buf_pool, block) + if (!buf_pool->is_block_field(block) || page_id != block->page.id || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index d33e1dd3c3a..2697afc2802 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1785,6 +1785,12 @@ void dict_sys_t::remove(dict_table_t* table, bool lru, bool keep) #ifdef BTR_CUR_HASH_ADAPT if (UNIV_UNLIKELY(UT_LIST_GET_LEN(table->freed_indexes) != 0)) { + if (table->fts) { + fts_optimize_remove_table(table); + fts_free(table); + table->fts = NULL; + } + table->vc_templ = NULL; table->id = 0; return; diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 70fa9c8245e..ddd2b99ef21 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -124,19 +124,22 @@ bool dict_col_t::same_encoding(uint16_t a, uint16_t b) return false; } -/**********************************************************************//** -Creates a table memory object. +/** Create a table memory object. +@param name table name +@param space tablespace +@param n_cols total number of columns (both virtual and non-virtual) +@param n_v_cols number of virtual columns +@param flags table flags +@param flags2 table flags2 @return own: table object */ dict_table_t* dict_mem_table_create( -/*==================*/ - const char* name, /*!< in: table name */ - fil_space_t* space, /*!< in: tablespace */ - ulint n_cols, /*!< in: total number of columns including - virtual and non-virtual columns */ - ulint n_v_cols,/*!< in: number of virtual columns */ - ulint flags, /*!< in: table flags */ - ulint flags2) /*!< in: table flags2 */ + const char* name, + fil_space_t* space, + ulint n_cols, + ulint n_v_cols, + ulint flags, + ulint flags2) { dict_table_t* table; mem_heap_t* heap; @@ -198,9 +201,6 @@ dict_mem_table_create( new(&table->foreign_set) dict_foreign_set(); new(&table->referenced_set) dict_foreign_set(); - rw_lock_create(dict_table_stats_key, &table->stats_latch, - SYNC_INDEX_TREE); - return(table); } @@ -245,8 +245,6 @@ dict_mem_table_free( UT_DELETE(table->s_cols); - rw_lock_free(&table->stats_latch); - mem_heap_free(table->heap); } diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index e593f1e8de2..950e33c090b 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -483,8 +483,6 @@ dict_stats_table_clone_create( ut_d(t->magic_n = DICT_TABLE_MAGIC_N); - rw_lock_create(dict_table_stats_key, &t->stats_latch, SYNC_INDEX_TREE); - return(t); } @@ -497,7 +495,6 @@ dict_stats_table_clone_free( /*========================*/ dict_table_t* t) /*!< in: dummy table object to free */ { - rw_lock_free(&t->stats_latch); mem_heap_free(t->heap); } @@ -514,7 +511,7 @@ dict_stats_empty_index( { ut_ad(!(index->type & DICT_FTS)); ut_ad(!dict_index_is_ibuf(index)); - ut_ad(rw_lock_own(&index->table->stats_latch, RW_LOCK_X)); + ut_ad(mutex_own(&dict_sys.mutex)); ulint n_uniq = index->n_uniq; @@ -544,10 +541,9 @@ dict_stats_empty_table( bool empty_defrag_stats) /*!< in: whether to empty defrag stats */ { - /* Zero the stats members */ - - rw_lock_x_lock(&table->stats_latch); + mutex_enter(&dict_sys.mutex); + /* Zero the stats members */ table->stat_n_rows = 0; table->stat_clustered_index_size = 1; /* 1 page for each index, not counting the clustered */ @@ -571,8 +567,7 @@ dict_stats_empty_table( } table->stat_initialized = TRUE; - - rw_lock_x_unlock(&table->stats_latch); + mutex_exit(&dict_sys.mutex); } /*********************************************************************//** @@ -671,6 +666,8 @@ dict_stats_copy( to have the same statistics as if the table was empty */ { + ut_ad(mutex_own(&dict_sys.mutex)); + dst->stats_last_recalc = src->stats_last_recalc; dst->stat_n_rows = src->stat_n_rows; dst->stat_clustered_index_size = src->stat_clustered_index_size; @@ -788,8 +785,6 @@ dict_stats_snapshot_create( { mutex_enter(&dict_sys.mutex); - rw_lock_s_lock(&table->stats_latch); - dict_stats_assert_initialized(table); dict_table_t* t; @@ -803,8 +798,6 @@ dict_stats_snapshot_create( t->stats_sample_pages = table->stats_sample_pages; t->stats_bg_flag = table->stats_bg_flag; - rw_lock_s_unlock(&table->stats_latch); - mutex_exit(&dict_sys.mutex); return(t); @@ -844,10 +837,14 @@ dict_stats_update_transient_for_index( Initialize some bogus index cardinality statistics, so that the data can be queried in various means, also via secondary indexes. */ + mutex_enter(&dict_sys.mutex); dict_stats_empty_index(index, false); + mutex_exit(&dict_sys.mutex); #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG } else if (ibuf_debug && !dict_index_is_clust(index)) { + mutex_enter(&dict_sys.mutex); dict_stats_empty_index(index, false); + mutex_exit(&dict_sys.mutex); #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ } else { mtr_t mtr; @@ -868,7 +865,9 @@ dict_stats_update_transient_for_index( switch (size) { case ULINT_UNDEFINED: + mutex_enter(&dict_sys.mutex); dict_stats_empty_index(index, false); + mutex_exit(&dict_sys.mutex); return; case 0: /* The root node of the tree is a leaf */ @@ -880,11 +879,23 @@ dict_stats_update_transient_for_index( /* Do not continue if table decryption has failed or table is already marked as corrupted. */ if (index->is_readable()) { - /* We don't handle the return value since it - will be false only when some thread is - dropping the table and we don't have to empty - the statistics of the to be dropped index */ - btr_estimate_number_of_different_key_vals(index); + std::vector<index_field_stats_t> stats + = btr_estimate_number_of_different_key_vals( + index); + + if (!stats.empty()) { + ut_ad(!mutex_own(&dict_sys.mutex)); + mutex_enter(&dict_sys.mutex); + for (size_t i = 0; i < stats.size(); ++i) { + index->stat_n_diff_key_vals[i] + = stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] + = stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] + = stats[i].n_non_null_key_vals; + } + mutex_exit(&dict_sys.mutex); + } } } } @@ -901,6 +912,8 @@ dict_stats_update_transient( /*========================*/ dict_table_t* table) /*!< in/out: table */ { + ut_ad(!mutex_own(&dict_sys.mutex)); + dict_index_t* index; ulint sum_of_index_sizes = 0; @@ -926,27 +939,25 @@ dict_stats_update_transient( ut_ad(!dict_index_is_ibuf(index)); - if (index->type & DICT_FTS || dict_index_is_spatial(index)) { + if (index->type & (DICT_FTS | DICT_SPATIAL)) { continue; } - dict_stats_empty_index(index, false); - - if (dict_stats_should_ignore_index(index)) { + if (dict_stats_should_ignore_index(index) + || !index->is_readable()) { + mutex_enter(&dict_sys.mutex); + dict_stats_empty_index(index, false); + mutex_exit(&dict_sys.mutex); continue; } - /* Do not continue if table decryption has failed or - table is already marked as corrupted. */ - if (!index->is_readable()) { - break; - } - dict_stats_update_transient_for_index(index); sum_of_index_sizes += index->stat_index_size; } + mutex_enter(&dict_sys.mutex); + index = dict_table_get_first_index(table); table->stat_n_rows = index->stat_n_diff_key_vals[ @@ -962,6 +973,8 @@ dict_stats_update_transient( table->stat_modified_counter = 0; table->stat_initialized = TRUE; + + mutex_exit(&dict_sys.mutex); } /* @{ Pseudo code about the relation between the following functions @@ -1806,16 +1819,31 @@ dict_stats_analyze_index_for_n_prefix( btr_pcur_close(&pcur); } +/** statistics for an index */ +struct index_stats_t +{ + std::vector<index_field_stats_t> stats; + ulint index_size; + ulint n_leaf_pages; + + index_stats_t(ulint n_uniq) : index_size(1), n_leaf_pages(1) + { + stats.reserve(n_uniq); + for (ulint i= 0; i < n_uniq; ++i) + stats.push_back(index_field_stats_t(0, 1, 0)); + } +}; + /** Set dict_index_t::stat_n_diff_key_vals[] and stat_n_sample_sizes[]. @param[in] n_diff_data input data to use to derive the results -@param[in,out] index index whose stat_n_diff_key_vals[] to set */ +@param[in,out] index_stats index stats to set */ UNIV_INLINE void dict_stats_index_set_n_diff( const n_diff_data_t* n_diff_data, - dict_index_t* index) + index_stats_t& index_stats) { - for (ulint n_prefix = dict_index_get_n_unique(index); + for (ulint n_prefix = index_stats.stats.size(); n_prefix >= 1; n_prefix--) { /* n_diff_all_analyzed_pages can be 0 here if @@ -1846,14 +1874,14 @@ dict_stats_index_set_n_diff( that the total number of ordinary leaf pages is T * D / (D + E). */ n_ordinary_leaf_pages - = index->stat_n_leaf_pages + = index_stats.n_leaf_pages * data->n_leaf_pages_to_analyze / (data->n_leaf_pages_to_analyze + data->n_external_pages_sum); } /* See REF01 for an explanation of the algorithm */ - index->stat_n_diff_key_vals[n_prefix - 1] + index_stats.stats[n_prefix - 1].n_diff_key_vals = n_ordinary_leaf_pages * data->n_diff_on_level @@ -1862,7 +1890,7 @@ dict_stats_index_set_n_diff( * data->n_diff_all_analyzed_pages / data->n_leaf_pages_to_analyze; - index->stat_n_sample_sizes[n_prefix - 1] + index_stats.stats[n_prefix - 1].n_sample_sizes = data->n_leaf_pages_to_analyze; DEBUG_PRINTF(" %s(): n_diff=" UINT64PF @@ -1871,9 +1899,9 @@ dict_stats_index_set_n_diff( " * " UINT64PF " / " UINT64PF " * " UINT64PF " / " UINT64PF ")\n", __func__, - index->stat_n_diff_key_vals[n_prefix - 1], + index_stats.stats[n_prefix - 1].n_diff_key_vals, n_prefix, - index->stat_n_leaf_pages, + index_stats.n_leaf_pages, data->n_diff_on_level, data->n_recs_on_level, data->n_diff_all_analyzed_pages, @@ -1881,15 +1909,12 @@ dict_stats_index_set_n_diff( } } -/*********************************************************************//** -Calculates new statistics for a given index and saves them to the index +/** Calculates new statistics for a given index and saves them to the index members stat_n_diff_key_vals[], stat_n_sample_sizes[], stat_index_size and -stat_n_leaf_pages. This function could be slow. */ -static -void -dict_stats_analyze_index( -/*=====================*/ - dict_index_t* index) /*!< in/out: index to analyze */ +stat_n_leaf_pages. This function can be slow. +@param[in] index index to analyze +@return index stats */ +static index_stats_t dict_stats_analyze_index(dict_index_t* index) { ulint root_level; ulint level; @@ -1900,26 +1925,28 @@ dict_stats_analyze_index( ib_uint64_t total_pages; mtr_t mtr; ulint size; + index_stats_t result(index->n_uniq); DBUG_ENTER("dict_stats_analyze_index"); DBUG_PRINT("info", ("index: %s, online status: %d", index->name(), dict_index_get_online_status(index))); + ut_ad(!mutex_own(&dict_sys.mutex)); // because this function is slow + ut_ad(index->table->get_ref_count()); + /* Disable update statistic for Rtree */ if (dict_index_is_spatial(index)) { - DBUG_VOID_RETURN; + DBUG_RETURN(result); } DEBUG_PRINTF(" %s(index=%s)\n", __func__, index->name()); - dict_stats_empty_index(index, false); - mtr.start(); mtr_s_lock_index(index, &mtr); size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); if (size != ULINT_UNDEFINED) { - index->stat_index_size = size; + result.index_size = size; size = btr_get_size(index, BTR_N_LEAF_PAGES, &mtr); } @@ -1929,13 +1956,13 @@ dict_stats_analyze_index( switch (size) { case ULINT_UNDEFINED: dict_stats_assert_initialized_index(index); - DBUG_VOID_RETURN; + DBUG_RETURN(result); case 0: /* The root node of the tree is a leaf */ size = 1; } - index->stat_n_leaf_pages = size; + result.n_leaf_pages = size; mtr.start(); mtr_sx_lock_index(index, &mtr); @@ -1974,14 +2001,18 @@ dict_stats_analyze_index( NULL /* boundaries not needed */, &mtr); + mtr.commit(); + + mutex_enter(&dict_sys.mutex); for (ulint i = 0; i < n_uniq; i++) { - index->stat_n_sample_sizes[i] = total_pages; + result.stats[i].n_diff_key_vals = index->stat_n_diff_key_vals[i]; + result.stats[i].n_sample_sizes = total_pages; + result.stats[i].n_non_null_key_vals = index->stat_n_non_null_key_vals[i]; } + result.n_leaf_pages = index->stat_n_leaf_pages; + mutex_exit(&dict_sys.mutex); - mtr.commit(); - - dict_stats_assert_initialized_index(index); - DBUG_VOID_RETURN; + DBUG_RETURN(result); } /* For each level that is being scanned in the btree, this contains the @@ -2173,13 +2204,12 @@ found_level: /* n_prefix == 0 means that the above loop did not end up prematurely due to tree being changed and so n_diff_data[] is set up. */ if (n_prefix == 0) { - dict_stats_index_set_n_diff(n_diff_data, index); + dict_stats_index_set_n_diff(n_diff_data, result); } UT_DELETE_ARRAY(n_diff_data); - dict_stats_assert_initialized_index(index); - DBUG_VOID_RETURN; + DBUG_RETURN(result); } /*********************************************************************//** @@ -2197,7 +2227,7 @@ dict_stats_update_persistent( DEBUG_PRINTF("%s(table=%s)\n", __func__, table->name); - rw_lock_x_lock(&table->stats_latch); + DEBUG_SYNC_C("dict_stats_update_persistent"); /* analyze the clustered index first */ @@ -2208,7 +2238,6 @@ dict_stats_update_persistent( || (index->type | DICT_UNIQUE) != (DICT_CLUSTERED | DICT_UNIQUE)) { /* Table definition is corrupt */ - rw_lock_x_unlock(&table->stats_latch); dict_stats_empty_table(table, true); return(DB_CORRUPTION); @@ -2216,7 +2245,16 @@ dict_stats_update_persistent( ut_ad(!dict_index_is_ibuf(index)); - dict_stats_analyze_index(index); + index_stats_t stats = dict_stats_analyze_index(index); + + mutex_enter(&dict_sys.mutex); + index->stat_index_size = stats.index_size; + index->stat_n_leaf_pages = stats.n_leaf_pages; + for (size_t i = 0; i < stats.stats.size(); ++i) { + index->stat_n_diff_key_vals[i] = stats.stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] = stats.stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] = stats.stats[i].n_non_null_key_vals; + } ulint n_unique = dict_index_get_n_unique(index); @@ -2234,7 +2272,7 @@ dict_stats_update_persistent( ut_ad(!dict_index_is_ibuf(index)); - if (index->type & DICT_FTS || dict_index_is_spatial(index)) { + if (index->type & (DICT_FTS | DICT_SPATIAL)) { continue; } @@ -2245,7 +2283,20 @@ dict_stats_update_persistent( } if (!(table->stats_bg_flag & BG_STAT_SHOULD_QUIT)) { - dict_stats_analyze_index(index); + mutex_exit(&dict_sys.mutex); + stats = dict_stats_analyze_index(index); + mutex_enter(&dict_sys.mutex); + + index->stat_index_size = stats.index_size; + index->stat_n_leaf_pages = stats.n_leaf_pages; + for (size_t i = 0; i < stats.stats.size(); ++i) { + index->stat_n_diff_key_vals[i] + = stats.stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] + = stats.stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] + = stats.stats[i].n_non_null_key_vals; + } } table->stat_sum_of_other_index_sizes @@ -2260,7 +2311,7 @@ dict_stats_update_persistent( dict_stats_assert_initialized(table); - rw_lock_x_unlock(&table->stats_latch); + mutex_exit(&dict_sys.mutex); return(DB_SUCCESS); } @@ -3077,11 +3128,22 @@ dict_stats_update_for_index( if (dict_stats_is_persistent_enabled(index->table)) { if (dict_stats_persistent_storage_check(false)) { - rw_lock_x_lock(&index->table->stats_latch); - dict_stats_analyze_index(index); + index_stats_t stats = dict_stats_analyze_index(index); + mutex_enter(&dict_sys.mutex); + index->stat_index_size = stats.index_size; + index->stat_n_leaf_pages = stats.n_leaf_pages; + for (size_t i = 0; i < stats.stats.size(); ++i) { + index->stat_n_diff_key_vals[i] + = stats.stats[i].n_diff_key_vals; + index->stat_n_sample_sizes[i] + = stats.stats[i].n_sample_sizes; + index->stat_n_non_null_key_vals[i] + = stats.stats[i].n_non_null_key_vals; + } index->table->stat_sum_of_other_index_sizes += index->stat_index_size; - rw_lock_x_unlock(&index->table->stats_latch); + mutex_exit(&dict_sys.mutex); + dict_stats_save(index->table, &index->id); DBUG_VOID_RETURN; } @@ -3102,9 +3164,7 @@ dict_stats_update_for_index( } } - rw_lock_x_lock(&index->table->stats_latch); dict_stats_update_transient_for_index(index); - rw_lock_x_unlock(&index->table->stats_latch); DBUG_VOID_RETURN; } @@ -3258,7 +3318,7 @@ dict_stats_update( switch (err) { case DB_SUCCESS: - rw_lock_x_lock(&table->stats_latch); + mutex_enter(&dict_sys.mutex); /* Pass reset_ignored_indexes=true as parameter to dict_stats_copy. This will cause statictics @@ -3267,7 +3327,7 @@ dict_stats_update( dict_stats_assert_initialized(table); - rw_lock_x_unlock(&table->stats_latch); + mutex_exit(&dict_sys.mutex); dict_stats_table_clone_free(t); @@ -3321,13 +3381,8 @@ dict_stats_update( } transient: - - rw_lock_x_lock(&table->stats_latch); - dict_stats_update_transient(table); - rw_lock_x_unlock(&table->stats_latch); - return(DB_SUCCESS); } diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 225561917a8..0d3bb1b0c0a 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -406,6 +406,8 @@ fil_space_crypt_t::write_page0( mlog_write_ulint(page + offset + MAGIC_SZ + 2 + len + 8, encryption, MLOG_1BYTE, mtr); + DBUG_EXECUTE_IF("ib_do_not_log_crypt_data", return;); + byte* log_ptr = mlog_open(mtr, 11 + 17 + len); if (log_ptr != NULL) { diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc index e22613a265b..6be4fb0d52b 100644 --- a/storage/innobase/fts/fts0ast.cc +++ b/storage/innobase/fts/fts0ast.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2007, 2020, 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 @@ -557,8 +557,7 @@ fts_ast_node_check_union( fts_ast_node_t* node) { if (node->type == FTS_AST_LIST - || node->type == FTS_AST_SUBEXP_LIST - || node->type == FTS_AST_PARSER_PHRASE_LIST) { + || node->type == FTS_AST_SUBEXP_LIST) { for (node = node->list.head; node; node = node->next) { if (!fts_ast_node_check_union(node)) { @@ -566,6 +565,9 @@ fts_ast_node_check_union( } } + } else if (node->type == FTS_AST_PARSER_PHRASE_LIST) { + /* Phrase search for plugin parser */ + return(false); } else if (node->type == FTS_AST_OPER && (node->oper == FTS_IGNORE || node->oper == FTS_EXIST)) { diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index a3e36f7d0da..8f212ff6676 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -4421,24 +4421,27 @@ fts_phrase_or_proximity_search( if (k == ib_vector_size(query->match_array[j])) { end_list = TRUE; - if (match[j]->doc_id != match[0]->doc_id) { - /* no match */ - if (query->flags & FTS_PHRASE) { - ulint s; + if (query->flags & FTS_PHRASE) { + ulint s; + /* Since i is the last doc id in the + match_array[j], remove all doc ids > i + from the match_array[0]. */ + fts_match_t* match_temp; + for (s = i + 1; s < n_matched; s++) { + match_temp = static_cast< + fts_match_t*>(ib_vector_get( + query->match_array[0], s)); + match_temp->doc_id = 0; + } + if (match[j]->doc_id != + match[0]->doc_id) { + /* no match */ match[0]->doc_id = 0; - - for (s = i + 1; s < n_matched; - s++) { - match[0] = static_cast< - fts_match_t*>( - ib_vector_get( - query->match_array[0], - s)); - match[0]->doc_id = 0; - } } + } + if (match[j]->doc_id != match[0]->doc_id) { goto func_exit; } } diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index b90e0444f45..849e080728f 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -1242,6 +1242,24 @@ rtr_check_discard_page( lock_mutex_exit(); } +/** Structure acts as functor to get the optimistic access of the page. +It returns true if it successfully gets the page. */ +struct optimistic_get +{ + btr_pcur_t *const r_cursor; + mtr_t *const mtr; + + optimistic_get(btr_pcur_t *r_cursor,mtr_t *mtr) + :r_cursor(r_cursor), mtr(mtr) {} + + bool operator()(buf_block_t *hint) const + { + return hint && buf_page_optimistic_get( + RW_X_LATCH, hint, r_cursor->modify_clock, __FILE__, + __LINE__, mtr); + } +}; + /** Restore the stored position of a persistent cursor bufferfixing the page */ static bool @@ -1275,11 +1293,8 @@ rtr_cur_restore_position( ut_ad(latch_mode == BTR_CONT_MODIFY_TREE); - if (!buf_pool_is_obsolete(r_cursor->withdraw_clock) - && buf_page_optimistic_get(RW_X_LATCH, - r_cursor->block_when_stored, - r_cursor->modify_clock, - __FILE__, __LINE__, mtr)) { + if (r_cursor->block_when_stored.run_with_hint( + optimistic_get(r_cursor, mtr))) { ut_ad(r_cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(r_cursor->rel_pos == BTR_PCUR_ON); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 519b86c8716..0585aaacb46 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -234,6 +234,27 @@ enum default_row_format_enum { DEFAULT_ROW_FORMAT_DYNAMIC = 2, }; +/** A dummy variable */ +static uint innodb_max_purge_lag_wait; + +/** Wait for trx_sys_t::rseg_history_len to be below a limit. */ +static void innodb_max_purge_lag_wait_update(THD *thd, st_mysql_sys_var *, + void *, const void *limit) +{ + const uint l= *static_cast<const uint*>(limit); + if (trx_sys.rseg_history_len <= l) + return; + mysql_mutex_unlock(&LOCK_global_system_variables); + while (trx_sys.rseg_history_len > l) + { + if (thd_kill_level(thd)) + break; + srv_wake_purge_thread_if_not_active(); + os_thread_sleep(100000); + } + mysql_mutex_lock(&LOCK_global_system_variables); +} + static void set_my_errno(int err) { @@ -656,7 +677,6 @@ static PSI_rwlock_info all_innodb_rwlocks[] = { PSI_RWLOCK_KEY(trx_purge_latch), PSI_RWLOCK_KEY(index_tree_rw_lock), PSI_RWLOCK_KEY(index_online_log), - PSI_RWLOCK_KEY(dict_table_stats), PSI_RWLOCK_KEY(hash_table_locks) }; # endif /* UNIV_PFS_RWLOCK */ @@ -14103,6 +14123,8 @@ ha_innobase::info_low( DEBUG_SYNC_C("ha_innobase_info_low"); + ut_ad(!mutex_own(&dict_sys.mutex)); + /* If we are forcing recovery at a high level, we will suppress statistics calculation on tables, because that may crash the server if an index is badly corrupted. */ @@ -14139,7 +14161,6 @@ ha_innobase::info_low( opt = DICT_STATS_RECALC_TRANSIENT; } - ut_ad(!mutex_own(&dict_sys.mutex)); ret = dict_stats_update(ib_table, opt); if (ret != DB_SUCCESS) { @@ -14155,14 +14176,14 @@ ha_innobase::info_low( stats.update_time = (ulong) ib_table->update_time; } + DBUG_EXECUTE_IF("dict_sys_mutex_avoid", goto func_exit;); + if (flag & HA_STATUS_VARIABLE) { ulint stat_clustered_index_size; ulint stat_sum_of_other_index_sizes; - if (!(flag & HA_STATUS_NO_LOCK)) { - rw_lock_s_lock(&ib_table->stats_latch); - } + mutex_enter(&dict_sys.mutex); ut_a(ib_table->stat_initialized); @@ -14174,9 +14195,7 @@ ha_innobase::info_low( stat_sum_of_other_index_sizes = ib_table->stat_sum_of_other_index_sizes; - if (!(flag & HA_STATUS_NO_LOCK)) { - rw_lock_s_unlock(&ib_table->stats_latch); - } + mutex_exit(&dict_sys.mutex); /* The MySQL optimizer seems to assume in a left join that n_rows @@ -14278,10 +14297,26 @@ ha_innobase::info_low( ib_push_frm_error(m_user_thd, ib_table, table, num_innodb_index, true); } - if (!(flag & HA_STATUS_NO_LOCK)) { - rw_lock_s_lock(&ib_table->stats_latch); + snprintf(path, sizeof(path), "%s/%s%s", + mysql_data_home, table->s->normalized_path.str, + reg_ext); + + unpack_filename(path,path); + + /* Note that we do not know the access time of the table, + nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ + + if (os_file_get_status( + path, &stat_info, false, + srv_read_only_mode) == DB_SUCCESS) { + stats.create_time = (ulong) stat_info.ctime; } + struct Locking { + Locking() { mutex_enter(&dict_sys.mutex); } + ~Locking() { mutex_exit(&dict_sys.mutex); } + } locking; + ut_a(ib_table->stat_initialized); for (i = 0; i < table->s->keys; i++) { @@ -14359,25 +14394,6 @@ ha_innobase::info_low( key->rec_per_key[j] = rec_per_key_int; } } - - if (!(flag & HA_STATUS_NO_LOCK)) { - rw_lock_s_unlock(&ib_table->stats_latch); - } - - snprintf(path, sizeof(path), "%s/%s%s", - mysql_data_home, table->s->normalized_path.str, - reg_ext); - - unpack_filename(path,path); - - /* Note that we do not know the access time of the table, - nor the CHECK TABLE time, nor the UPDATE or INSERT time. */ - - if (os_file_get_status( - path, &stat_info, false, - srv_read_only_mode) == DB_SUCCESS) { - stats.create_time = (ulong) stat_info.ctime; - } } if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { @@ -19021,6 +19037,11 @@ static MYSQL_SYSVAR_ULONG(max_purge_lag_delay, srv_max_purge_lag_delay, 0L, /* Minimum value */ 10000000UL, 0); /* Maximum value */ +static MYSQL_SYSVAR_UINT(max_purge_lag_wait, innodb_max_purge_lag_wait, + PLUGIN_VAR_RQCMDARG, + "Wait until History list length is below the specified limit", + NULL, innodb_max_purge_lag_wait_update, UINT_MAX, 0, UINT_MAX, 0); + static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, "Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)", @@ -19119,10 +19140,10 @@ static MYSQL_SYSVAR_BOOL(log_compressed_pages, page_zip_log_pages, static MYSQL_SYSVAR_BOOL(log_optimize_ddl, innodb_log_optimize_ddl, PLUGIN_VAR_OPCMDARG, - "Reduce redo logging when natively creating indexes or rebuilding tables." - " Setting this OFF avoids delay due to page flushing and" - " allows concurrent backup.", - NULL, NULL, TRUE); + "DEPRECATED. Ignored in MariaDB 10.5." + " Reduce redo logging when natively creating indexes or rebuilding tables." + " Enabling this may slow down backup and cause delay due to page flushing.", + NULL, NULL, FALSE); static MYSQL_SYSVAR_ULONG(autoextend_increment, sys_tablespace_auto_extend_increment, @@ -20041,6 +20062,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(flushing_avg_loops), MYSQL_SYSVAR(max_purge_lag), MYSQL_SYSVAR(max_purge_lag_delay), + MYSQL_SYSVAR(max_purge_lag_wait), MYSQL_SYSVAR(old_blocks_pct), MYSQL_SYSVAR(old_blocks_time), MYSQL_SYSVAR(open_files), diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 8127effb304..fb3e79b4f89 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6267,38 +6267,43 @@ i_s_dict_fill_sys_tablestats( OK(field_store_string(fields[SYS_TABLESTATS_NAME], table->name.m_name)); - rw_lock_s_lock(&table->stats_latch); + { + struct Locking + { + Locking() { mutex_enter(&dict_sys.mutex); } + ~Locking() { mutex_exit(&dict_sys.mutex); } + } locking; - if (table->stat_initialized) { - OK(field_store_string(fields[SYS_TABLESTATS_INIT], - "Initialized")); + if (table->stat_initialized) { + OK(field_store_string(fields[SYS_TABLESTATS_INIT], + "Initialized")); - OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows, - true)); + OK(fields[SYS_TABLESTATS_NROW]->store( + table->stat_n_rows, true)); - OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store( - table->stat_clustered_index_size, true)); + OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store( + table->stat_clustered_index_size, true)); - OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store( - table->stat_sum_of_other_index_sizes, true)); + OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store( + table->stat_sum_of_other_index_sizes, + true)); - OK(fields[SYS_TABLESTATS_MODIFIED]->store( - table->stat_modified_counter, true)); - } else { - OK(field_store_string(fields[SYS_TABLESTATS_INIT], - "Uninitialized")); + OK(fields[SYS_TABLESTATS_MODIFIED]->store( + table->stat_modified_counter, true)); + } else { + OK(field_store_string(fields[SYS_TABLESTATS_INIT], + "Uninitialized")); - OK(fields[SYS_TABLESTATS_NROW]->store(0, true)); + OK(fields[SYS_TABLESTATS_NROW]->store(0, true)); - OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true)); + OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true)); - OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true)); + OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true)); - OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true)); + OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true)); + } } - rw_lock_s_unlock(&table->stats_latch); - OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true)); OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(ref_count, true)); diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 29382bb033f..fe845005536 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -214,7 +214,7 @@ the index. ulint btr_height_get( /*===========*/ - dict_index_t* index, /*!< in: index tree */ + const dict_index_t* index, /*!< in: index tree */ mtr_t* mtr) /*!< in/out: mini-transaction */ MY_ATTRIBUTE((warn_unused_result)); @@ -592,7 +592,7 @@ Gets the number of pages in a B-tree. ulint btr_get_size( /*=========*/ - dict_index_t* index, /*!< in: index */ + const dict_index_t* index, /*!< in: index */ ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ mtr_t* mtr) /*!< in/out: mini-transaction where index is s-latched */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 12aaa73ae30..1f1ac2a09e7 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -614,8 +614,24 @@ btr_estimate_n_rows_in_range( const dtuple_t* tuple2, page_cur_mode_t mode2); -/*******************************************************************//** -Estimates the number of different key values in a given index, for + +/** Statistics for one field of an index. */ +struct index_field_stats_t +{ + ib_uint64_t n_diff_key_vals; + ib_uint64_t n_sample_sizes; + ib_uint64_t n_non_null_key_vals; + + index_field_stats_t(ib_uint64_t n_diff_key_vals= 0, + ib_uint64_t n_sample_sizes= 0, + ib_uint64_t n_non_null_key_vals= 0) + : n_diff_key_vals(n_diff_key_vals), n_sample_sizes(n_sample_sizes), + n_non_null_key_vals(n_non_null_key_vals) + { + } +}; + +/** Estimates the number of different key values in a given index, for each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index). The estimates are stored in the array index->stat_n_diff_key_vals[] (indexed 0..n_uniq-1) and the number of pages that were sampled is saved in @@ -623,12 +639,11 @@ index->stat_n_sample_sizes[]. If innodb_stats_method is nulls_ignored, we also record the number of non-null values for each prefix and stored the estimates in array index->stat_n_non_null_key_vals. -@return true if the index is available and we get the estimated numbers, -false if the index is unavailable. */ -bool -btr_estimate_number_of_different_key_vals( -/*======================================*/ - dict_index_t* index); /*!< in: index */ +@param[in] index index +@return stat vector if the index is available and we get the estimated numbers, +empty vector if the index is unavailable. */ +std::vector<index_field_stats_t> +btr_estimate_number_of_different_key_vals(dict_index_t* index); /** Gets the externally stored size of a record, in units of a database page. @param[in] rec record diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index c20b971de98..38960b1d15c 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -29,6 +29,7 @@ Created 2/23/1996 Heikki Tuuri #include "dict0dict.h" #include "btr0cur.h" +#include "buf0block_hint.h" #include "btr0btr.h" #include "gis0rtree.h" @@ -502,13 +503,10 @@ struct btr_pcur_t{ whether cursor was on, before, or after the old_rec record */ enum btr_pcur_pos_t rel_pos; /** buffer block when the position was stored */ - buf_block_t* block_when_stored; + buf::Block_hint block_when_stored; /** the modify clock value of the buffer block when the cursor position was stored */ ib_uint64_t modify_clock; - /** the withdraw clock value of the buffer pool when the cursor - position was stored */ - ulint withdraw_clock; /** btr_pcur_store_position() and btr_pcur_restore_position() state. */ enum pcur_pos_t pos_state; /** PAGE_CUR_G, ... */ @@ -528,9 +526,8 @@ struct btr_pcur_t{ 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), + block_when_stored(), + modify_clock(0), pos_state(BTR_PCUR_NOT_POSITIONED), search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL), old_rec_buf(NULL), buf_size(0) { diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index 2fa9aaa38fe..adb14a7c16f 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -206,8 +206,6 @@ struct btr_search_t{ the machine word, i.e., they cannot be turned into bit-fields. */ buf_block_t* root_guess;/*!< the root page frame when it was last time fetched, or NULL */ - ulint withdraw_clock; /*!< the withdraw clock value of the buffer - pool when root_guess was stored */ #ifdef BTR_CUR_HASH_ADAPT ulint hash_analysis; /*!< when this exceeds BTR_SEARCH_HASH_ANALYSIS, the hash diff --git a/storage/innobase/include/buf0block_hint.h b/storage/innobase/include/buf0block_hint.h new file mode 100644 index 00000000000..2d681175b25 --- /dev/null +++ b/storage/innobase/include/buf0block_hint.h @@ -0,0 +1,77 @@ +/***************************************************************************** + +Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2020, MariaDB Corporation. +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License, version 2.0, as published by the +Free Software Foundation. + +This program is also distributed with certain software (including but not +limited to OpenSSL) that is licensed under separate terms, as designated in a +particular file or component or in included license documentation. The authors +of MySQL hereby grant you an additional permission to link the program and +your derivative works with the separately licensed software that they have +included with MySQL. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, +for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*****************************************************************************/ +#pragma once +#include "buf0buf.h" + +namespace buf { +class Block_hint { + public: + Block_hint():m_block(NULL),m_page_id(0,0) {} + /** Stores the pointer to the block, which is currently buffer-fixed. + @param block a pointer to a buffer-fixed block to be stored */ + inline void store(buf_block_t *block) + { + ut_ad(block->page.buf_fix_count); + m_block= block; + m_page_id= block->page.id; + } + + /** Clears currently stored pointer. */ + inline void clear() { m_block= NULL; } + + /** Invoke f on m_block(which may be null) + @param f The function to be executed. It will be passed the pointer. + If you wish to use the block pointer subsequently, + you need to ensure you buffer-fix it before returning from f. + @return the return value of f + */ + template <typename F> + bool run_with_hint(const F &f) + { + buffer_fix_block_if_still_valid(); + /* m_block could be changed during f() call, so we use local + variable to remember which block we need to unfix */ + buf_block_t *block= m_block; + bool res= f(block); + if (block) + buf_block_buf_fix_dec(block); + return res; + } + + buf_block_t *block() const { return m_block; } + + private: + /** The block pointer stored by store(). */ + buf_block_t *m_block; + /** If m_block is non-null, the m_block->page.id at time it was stored. */ + page_id_t m_page_id; + + /** A helper function which checks if m_block is not a dangling pointer and + still points to block with page with m_page_id and if so, buffer-fixes it, + otherwise clear()s it */ + void buffer_fix_block_if_still_valid(); +}; +} // namespace buf diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 2c8421c8bf4..28060ec601e 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -100,10 +100,6 @@ extern buf_pool_t* buf_pool_ptr; /*!< The buffer pools extern volatile bool buf_pool_withdrawing; /*!< true when withdrawing buffer pool pages might cause page relocation */ -extern volatile ulint buf_withdraw_clock; /*!< the clock is incremented - every time a pointer to a page may - become obsolete */ - # ifdef UNIV_DEBUG extern my_bool buf_disable_resize_buffer_pool_debug; /*!< if TRUE, resizing buffer pool is not allowed. */ @@ -1394,14 +1390,6 @@ buf_get_nth_chunk_block( ulint n, /*!< in: nth chunk in the buffer pool */ ulint* chunk_size); /*!< in: chunk size */ -/** Verify the possibility that a stored page is not in buffer pool. -@param[in] withdraw_clock withdraw clock when stored the page -@retval true if the page might be relocated */ -UNIV_INLINE -bool -buf_pool_is_obsolete( - ulint withdraw_clock); - /** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit, if needed. @param[in] size size in bytes @@ -2284,6 +2272,12 @@ struct buf_pool_t{ return NULL; } } io_buf; + + /** Determine if a pointer belongs to a buf_block_t. + It can be a pointer to the buf_block_t itself or a member of it. + @param ptr a pointer that will not be dereferenced + @return whether the ptr belongs to a buf_block_t struct */ + inline bool is_block_field(const void *ptr) const; }; /** Print the given buf_pool_t object. diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 7d11e2b4cc0..9fcac6e2695 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -2,7 +2,7 @@ Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2014, 2019, MariaDB Corporation. +Copyright (c) 2014, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -54,6 +54,25 @@ struct buf_chunk_t{ } }; +bool buf_pool_t::is_block_field(const void *ptr) const +{ + const buf_chunk_t* chunk= chunks; + const buf_chunk_t *const echunk= chunk + ut_min(n_chunks, + n_chunks_new); + /* TODO: protect chunks with a mutex (the older pointer will + currently remain during resize()) */ + while (chunk < echunk) + { + if (ptr >= reinterpret_cast<const void*>(chunk->blocks) && + ptr < reinterpret_cast<const void*>( + chunk->blocks + chunk->size)) + return true; + chunk++; + } + + return false; +} + /*********************************************************************//** Gets the current size of buffer buf_pool in bytes. @return size in bytes */ @@ -989,8 +1008,6 @@ buf_block_buf_fix_dec( /*==================*/ buf_block_t* block) /*!< in/out: block to bufferunfix */ { - block->unfix(); - #ifdef UNIV_DEBUG /* No debug latch is acquired if block belongs to system temporary. Debug latch is not of much help if access to block is single @@ -999,6 +1016,8 @@ buf_block_buf_fix_dec( rw_lock_s_unlock(block->debug_latch); } #endif /* UNIV_DEBUG */ + + block->unfix(); } /** Returns the buffer pool instance given a page id. @@ -1372,18 +1391,6 @@ buf_page_get_frame( } } -/** Verify the possibility that a stored page is not in buffer pool. -@param[in] withdraw_clock withdraw clock when stored the page -@retval true if the page might be relocated */ -UNIV_INLINE -bool -buf_pool_is_obsolete( - ulint withdraw_clock) -{ - return(UNIV_UNLIKELY(buf_pool_withdrawing - || buf_withdraw_clock != withdraw_clock)); -} - /** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit, if needed. @param[in] size size in bytes diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index c5f1ef96ea6..6bb86269856 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -2,7 +2,7 @@ Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, 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 @@ -1265,7 +1265,7 @@ UNIV_INLINE rw_lock_t* dict_index_get_lock( /*================*/ - dict_index_t* index) /*!< in: index */ + const dict_index_t* index) /*!< in: index */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /********************************************************************//** Returns free space reserved for future updates of records. This is diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index b6d15f28a69..d00f4f8f6a3 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -938,7 +938,7 @@ UNIV_INLINE rw_lock_t* dict_index_get_lock( /*================*/ - dict_index_t* index) /*!< in: index */ + const dict_index_t* index) /*!< in: index */ { ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 929311bbc90..c6a506472df 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -297,20 +297,23 @@ parent table will fail, and user has to drop excessive foreign constraint before proceeds. */ #define FK_MAX_CASCADE_DEL 15 -/**********************************************************************//** -Creates a table memory object. +/** Create a table memory object. +@param name table name +@param space tablespace +@param n_cols total number of columns (both virtual and non-virtual) +@param n_v_cols number of virtual columns +@param flags table flags +@param flags2 table flags2 @return own: table object */ dict_table_t* dict_mem_table_create( -/*==================*/ - const char* name, /*!< in: table name */ - fil_space_t* space, /*!< in: tablespace */ - ulint n_cols, /*!< in: total number of columns - including virtual and non-virtual - columns */ - ulint n_v_cols, /*!< in: number of virtual columns */ - ulint flags, /*!< in: table flags */ - ulint flags2); /*!< in: table flags2 */ + const char* name, + fil_space_t* space, + ulint n_cols, + ulint n_v_cols, + ulint flags, + ulint flags2); + /****************************************************************//** Free a table memory object. */ void @@ -1118,7 +1121,7 @@ public: when InnoDB was started up */ zip_pad_info_t zip_pad;/*!< Information about state of compression failures and successes */ - rw_lock_t lock; /*!< read-write lock protecting the + mutable rw_lock_t lock; /*!< read-write lock protecting the upper levels of the index tree */ /** Determine if the index has been committed to the @@ -2102,20 +2105,8 @@ public: /*!< set of foreign key constraints which refer to this table */ dict_foreign_set referenced_set; - /** Statistics for query optimization. @{ */ - - /** This latch protects: - dict_table_t::stat_initialized, - dict_table_t::stat_n_rows (*), - dict_table_t::stat_clustered_index_size, - dict_table_t::stat_sum_of_other_index_sizes, - dict_table_t::stat_modified_counter (*), - dict_table_t::indexes*::stat_n_diff_key_vals[], - dict_table_t::indexes*::stat_index_size, - dict_table_t::indexes*::stat_n_leaf_pages. - (*) Those are not always protected for - performance reasons. */ - rw_lock_t stats_latch; + /** Statistics for query optimization. Mostly protected by + dict_sys.mutex. @{ */ /** TRUE if statistics have been calculated the first time after database startup or table creation. */ diff --git a/storage/innobase/include/dict0stats.ic b/storage/innobase/include/dict0stats.ic index 34e5aedb127..d4e23ecb0a4 100644 --- a/storage/innobase/include/dict0stats.ic +++ b/storage/innobase/include/dict0stats.ic @@ -75,7 +75,7 @@ dict_stats_is_persistent_enabled(const dict_table_t* table) + dict_stats_update(DICT_STATS_RECALC_TRANSIENT) on a table that has just been PS-enabled. This is acceptable. Avoiding this would mean that we would have to - protect the ::stat_persistent with dict_table_t::stats_latch like the + protect the stat_persistent with dict_sys.mutex like the other ::stat_ members which would be too big performance penalty, especially when this function is called from dict_stats_update_if_needed(). */ @@ -178,10 +178,7 @@ dict_stats_deinit( ut_a(table->get_ref_count() == 0); - rw_lock_x_lock(&table->stats_latch); - if (!table->stat_initialized) { - rw_lock_x_unlock(&table->stats_latch); return; } @@ -221,6 +218,4 @@ dict_stats_deinit( sizeof(index->stat_n_leaf_pages)); } #endif /* HAVE_valgrind */ - - rw_lock_x_unlock(&table->stats_latch); } diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index fe76d4cc271..deb1e977404 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -170,10 +170,10 @@ mtr_t::release_block_at_savepoint( ut_a(slot->object == block); - reinterpret_cast<buf_block_t*>(block)->unfix(); - buf_page_release_latch(block, slot->type); + reinterpret_cast<buf_block_t*>(block)->unfix(); + slot->object = NULL; } diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index f930320b30c..c9cf963b840 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -122,7 +122,6 @@ extern mysql_pfs_key_t trx_i_s_cache_lock_key; extern mysql_pfs_key_t trx_purge_latch_key; extern mysql_pfs_key_t index_tree_rw_lock_key; extern mysql_pfs_key_t index_online_log_key; -extern mysql_pfs_key_t dict_table_stats_key; extern mysql_pfs_key_t trx_sys_rw_lock_key; extern mysql_pfs_key_t hash_table_locks_key; #endif /* UNIV_PFS_RWLOCK */ diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 2da9256c77d..6ba457cdc40 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, 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 diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index ce92e5de5e1..604560af3e9 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, 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 @@ -360,8 +360,6 @@ struct trx_undo_t { (IB_ID_MAX if the undo log is empty) */ buf_block_t* guess_block; /*!< guess for the buffer block where the top page might reside */ - ulint withdraw_clock; /*!< the withdraw clock value of the - buffer pool when guess_block was stored */ /** @return whether the undo log is empty */ bool empty() const { return top_undo_no == IB_ID_MAX; } diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 15d7cc4b5a4..5ca74659813 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -233,8 +233,8 @@ static void memo_slot_release(mtr_memo_slot_t *slot) case MTR_MEMO_PAGE_SX_FIX: case MTR_MEMO_PAGE_X_FIX: buf_block_t *block= reinterpret_cast<buf_block_t*>(slot->object); - block->unfix(); buf_page_release_latch(block, slot->type); + block->unfix(); break; } slot->object= NULL; @@ -276,8 +276,8 @@ struct ReleaseLatches { case MTR_MEMO_PAGE_SX_FIX: case MTR_MEMO_PAGE_X_FIX: buf_block_t *block= reinterpret_cast<buf_block_t*>(slot->object); - block->unfix(); buf_page_release_latch(block, slot->type); + block->unfix(); break; } slot->object= NULL; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index a4359b9f7ad..ea0719a3fc8 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1523,7 +1523,7 @@ error_exit: srv_stats.n_rows_inserted.inc(size_t(trx->id)); } - /* Not protected by dict_table_stats_lock() for performance + /* Not protected by dict_sys.mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than protecting the following code with a latch. */ @@ -1893,7 +1893,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt) ut_ad(is_delete == (node->is_delete == PLAIN_DELETE)); if (is_delete) { - /* Not protected by dict_table_stats_lock() for performance + /* Not protected by dict_sys.mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than protecting the following code with a latch. */ @@ -2244,8 +2244,7 @@ row_update_cascade_for_mysql( bool stats; if (node->is_delete == PLAIN_DELETE) { - /* Not protected by - dict_table_stats_lock() for + /* Not protected by dict_sys.mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index ed5f2c069da..b199469e5d5 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -589,7 +589,7 @@ row_undo_ins( } if (err == DB_SUCCESS && node->table->stat_initialized) { - /* Not protected by dict_table_stats_lock() for + /* Not protected by dict_sys.mutex for performance reasons, we would rather get garbage in stat_n_rows (which is just an estimate anyway) than protecting the following code with a latch. */ diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index f2c7e3abd13..a00c9cef5af 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -1446,9 +1446,6 @@ sync_latch_meta_init() LATCH_ADD_RWLOCK(INDEX_TREE, SYNC_INDEX_TREE, index_tree_rw_lock_key); - LATCH_ADD_RWLOCK(DICT_TABLE_STATS, SYNC_INDEX_TREE, - dict_table_stats_key); - LATCH_ADD_RWLOCK(HASH_TABLE_RW_LOCK, SYNC_BUF_PAGE_HASH, hash_table_locks_key); diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 99688964387..e7be502632d 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -97,7 +97,6 @@ mysql_pfs_key_t buf_block_debug_latch_key; # endif /* UNIV_DEBUG */ mysql_pfs_key_t checkpoint_lock_key; mysql_pfs_key_t dict_operation_lock_key; -mysql_pfs_key_t dict_table_stats_key; mysql_pfs_key_t hash_table_locks_key; mysql_pfs_key_t index_tree_rw_lock_key; mysql_pfs_key_t index_online_log_key; diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 310d071d368..eb7d0967901 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -2030,7 +2030,6 @@ dberr_t trx_undo_report_rename(trx_t* trx, const dict_table_t* table) if (ulint offset = trx_undo_page_report_rename( trx, table, block, &mtr)) { - undo->withdraw_clock = buf_withdraw_clock; undo->top_page_no = undo->last_page_no; undo->top_offset = offset; undo->top_undo_no = trx->undo_no++; @@ -2170,7 +2169,6 @@ trx_undo_report_row_operation( mtr_commit(&mtr); } else { /* Success */ - undo->withdraw_clock = buf_withdraw_clock; mtr_commit(&mtr); undo->top_page_no = undo_block->page.id.page_no(); diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index da219cf6139..6128044bbc9 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1223,7 +1223,6 @@ trx_undo_mem_create( undo->top_undo_no = IB_ID_MAX; undo->top_page_no = page_no; undo->guess_block = NULL; - undo->withdraw_clock = 0; ut_ad(undo->empty()); return(undo); @@ -1412,9 +1411,7 @@ trx_undo_assign(trx_t* trx, dberr_t* err, mtr_t* mtr) if (undo) { return buf_page_get_gen( page_id_t(undo->rseg->space->id, undo->last_page_no), - 0, RW_X_LATCH, - buf_pool_is_obsolete(undo->withdraw_clock) - ? NULL : undo->guess_block, + 0, RW_X_LATCH, undo->guess_block, BUF_GET, __FILE__, __LINE__, mtr, err); } @@ -1468,9 +1465,7 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo, if (*undo) { return buf_page_get_gen( page_id_t(rseg->space->id, (*undo)->last_page_no), - 0, RW_X_LATCH, - buf_pool_is_obsolete((*undo)->withdraw_clock) - ? NULL : (*undo)->guess_block, + 0, RW_X_LATCH, (*undo)->guess_block, BUF_GET, __FILE__, __LINE__, mtr, err); } |