diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-28 10:44:40 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-28 10:44:40 +0200 |
commit | 2b6f8044903dc974c32e071bc6a7c4099481ae80 (patch) | |
tree | 3f72286d31780f41c394889daea8433c7f603a75 /storage | |
parent | a8de8f261d1b7621b8e16396e87dfaac14891162 (diff) | |
parent | cc5f4428b8b568f98e967a57178efcaf78702168 (diff) | |
download | mariadb-git-2b6f8044903dc974c32e071bc6a7c4099481ae80.tar.gz |
Merge 10.2 into 10.3
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 4 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 46 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.cc | 50 | ||||
-rw-r--r-- | storage/innobase/dict/dict0mem.cc | 14 | ||||
-rw-r--r-- | storage/innobase/dict/dict0stats.cc | 210 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 54 | ||||
-rw-r--r-- | storage/innobase/handler/i_s.cc | 47 | ||||
-rw-r--r-- | storage/innobase/ibuf/ibuf0ibuf.cc | 2 | ||||
-rw-r--r-- | storage/innobase/include/btr0btr.h | 4 | ||||
-rw-r--r-- | storage/innobase/include/btr0cur.h | 31 | ||||
-rw-r--r-- | storage/innobase/include/btr0sea.h | 2 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.h | 18 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.ic | 2 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 25 | ||||
-rw-r--r-- | storage/innobase/include/dict0stats.ic | 7 | ||||
-rw-r--r-- | storage/innobase/include/sync0sync.h | 1 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.cc | 6 | ||||
-rw-r--r-- | storage/innobase/row/row0uins.cc | 2 | ||||
-rw-r--r-- | storage/innobase/sync/sync0debug.cc | 3 | ||||
-rw-r--r-- | storage/innobase/sync/sync0sync.cc | 1 |
20 files changed, 246 insertions, 283 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index d5d1f30fa67..ebe6bf57d15 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -284,7 +284,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; @@ -591,7 +591,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/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index d300c01fe90..6f91d7ac898 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -6558,21 +6558,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; @@ -6592,11 +6590,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); @@ -6705,7 +6703,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 @@ -6811,8 +6809,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); @@ -6833,25 +6835,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/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 2e165a3a7bc..848b377586c 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -262,56 +262,6 @@ dict_mutex_exit_for_mysql(void) mutex_exit(&dict_sys->mutex); } -/** Lock the appropriate latch to protect a given table's statistics. -@param[in] table table whose stats to lock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_lock( - dict_table_t* table, - ulint latch_mode) -{ - ut_ad(table != NULL); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - switch (latch_mode) { - case RW_S_LATCH: - rw_lock_s_lock(&table->stats_latch); - break; - case RW_X_LATCH: - rw_lock_x_lock(&table->stats_latch); - break; - case RW_NO_LATCH: - /* fall through */ - default: - ut_error; - } -} - -/** Unlock the latch that has been locked by dict_table_stats_lock(). -@param[in] table table whose stats to unlock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_unlock( - dict_table_t* table, - ulint latch_mode) -{ - ut_ad(table != NULL); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - - switch (latch_mode) { - case RW_S_LATCH: - rw_lock_s_unlock(&table->stats_latch); - break; - case RW_X_LATCH: - rw_lock_x_unlock(&table->stats_latch); - break; - case RW_NO_LATCH: - /* fall through */ - default: - ut_error; - } -} - /**********************************************************************//** Try to drop any indexes after an aborted index creation. This can also be after a server kill during DROP INDEX. */ diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index a7201f165c0..8e0edf1cf3f 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -122,7 +122,6 @@ operator<<( @param n_v_cols number of virtual columns @param flags table flags @param flags2 table flags2 -@param init_stats_latch whether to init the stats latch @return own: table object */ dict_table_t* dict_mem_table_create( @@ -131,8 +130,7 @@ dict_mem_table_create( ulint n_cols, ulint n_v_cols, ulint flags, - ulint flags2, - bool init_stats_latch) + ulint flags2) { dict_table_t* table; mem_heap_t* heap; @@ -193,12 +191,6 @@ dict_mem_table_create( new(&table->foreign_set) dict_foreign_set(); new(&table->referenced_set) dict_foreign_set(); - if (init_stats_latch) { - rw_lock_create(dict_table_stats_key, &table->stats_latch, - SYNC_INDEX_TREE); - table->stats_latch_inited = true; - } - return(table); } @@ -248,10 +240,6 @@ dict_mem_table_free( UT_DELETE(table->s_cols); } - if (table->stats_latch_inited) { - 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 2c0ba38886f..84207814fab 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -484,8 +484,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); } @@ -498,15 +496,12 @@ 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); } /*********************************************************************//** Write all zeros (or 1 where it makes sense) into an index -statistics members. The resulting stats correspond to an empty index. -The caller must own index's table stats latch in X mode -(dict_table_stats_lock(table, RW_X_LATCH)) */ +statistics members. The resulting stats correspond to an empty index. */ static void dict_stats_empty_index( @@ -517,6 +512,7 @@ dict_stats_empty_index( { ut_ad(!(index->type & DICT_FTS)); ut_ad(!dict_index_is_ibuf(index)); + ut_ad(mutex_own(&dict_sys->mutex)); ulint n_uniq = index->n_uniq; @@ -546,10 +542,9 @@ dict_stats_empty_table( bool empty_defrag_stats) /*!< in: whether to empty defrag stats */ { - /* Zero the stats members */ - - dict_table_stats_lock(table, RW_X_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 */ @@ -573,8 +568,7 @@ dict_stats_empty_table( } table->stat_initialized = TRUE; - - dict_table_stats_unlock(table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); } /*********************************************************************//** @@ -673,6 +667,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; @@ -790,8 +786,6 @@ dict_stats_snapshot_create( { mutex_enter(&dict_sys->mutex); - dict_table_stats_lock(table, RW_S_LATCH); - dict_stats_assert_initialized(table); dict_table_t* t; @@ -805,8 +799,6 @@ dict_stats_snapshot_create( t->stats_sample_pages = table->stats_sample_pages; t->stats_bg_flag = table->stats_bg_flag; - dict_table_stats_unlock(table, RW_S_LATCH); - mutex_exit(&dict_sys->mutex); return(t); @@ -846,10 +838,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; @@ -870,7 +866,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 */ @@ -882,11 +880,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); + } } } } @@ -903,6 +913,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; @@ -928,27 +940,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[ @@ -964,6 +974,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 @@ -1808,16 +1820,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 @@ -1848,14 +1875,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 @@ -1864,7 +1891,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 @@ -1873,9 +1900,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, @@ -1883,15 +1910,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; @@ -1902,26 +1926,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); } @@ -1931,13 +1957,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); @@ -1976,14 +2002,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 @@ -2175,13 +2205,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); } /*********************************************************************//** @@ -2199,7 +2228,7 @@ dict_stats_update_persistent( DEBUG_PRINTF("%s(table=%s)\n", __func__, table->name); - dict_table_stats_lock(table, RW_X_LATCH); + DEBUG_SYNC_C("dict_stats_update_persistent"); /* analyze the clustered index first */ @@ -2210,7 +2239,6 @@ dict_stats_update_persistent( || (index->type | DICT_UNIQUE) != (DICT_CLUSTERED | DICT_UNIQUE)) { /* Table definition is corrupt */ - dict_table_stats_unlock(table, RW_X_LATCH); dict_stats_empty_table(table, true); return(DB_CORRUPTION); @@ -2218,7 +2246,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); @@ -2236,7 +2273,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; } @@ -2247,7 +2284,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 @@ -2262,7 +2312,7 @@ dict_stats_update_persistent( dict_stats_assert_initialized(table); - dict_table_stats_unlock(table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); return(DB_SUCCESS); } @@ -3090,11 +3140,22 @@ dict_stats_update_for_index( if (dict_stats_is_persistent_enabled(index->table)) { if (dict_stats_persistent_storage_check(false)) { - dict_table_stats_lock(index->table, RW_X_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; - dict_table_stats_unlock(index->table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); + dict_stats_save(index->table, &index->id); DBUG_VOID_RETURN; } @@ -3115,9 +3176,7 @@ dict_stats_update_for_index( } } - dict_table_stats_lock(index->table, RW_X_LATCH); dict_stats_update_transient_for_index(index); - dict_table_stats_unlock(index->table, RW_X_LATCH); DBUG_VOID_RETURN; } @@ -3271,7 +3330,7 @@ dict_stats_update( switch (err) { case DB_SUCCESS: - dict_table_stats_lock(table, RW_X_LATCH); + mutex_enter(&dict_sys->mutex); /* Pass reset_ignored_indexes=true as parameter to dict_stats_copy. This will cause statictics @@ -3280,7 +3339,7 @@ dict_stats_update( dict_stats_assert_initialized(table); - dict_table_stats_unlock(table, RW_X_LATCH); + mutex_exit(&dict_sys->mutex); dict_stats_table_clone_free(t); @@ -3334,13 +3393,8 @@ dict_stats_update( } transient: - - dict_table_stats_lock(table, RW_X_LATCH); - dict_stats_update_transient(table); - dict_table_stats_unlock(table, RW_X_LATCH); - return(DB_SUCCESS); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0be3a532e69..9db02a5b9a7 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -695,7 +695,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 */ @@ -14117,6 +14116,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. */ @@ -14153,7 +14154,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) { @@ -14169,14 +14169,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)) { - dict_table_stats_lock(ib_table, RW_S_LATCH); - } + mutex_enter(&dict_sys->mutex); ut_a(ib_table->stat_initialized); @@ -14188,9 +14188,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)) { - dict_table_stats_unlock(ib_table, RW_S_LATCH); - } + mutex_exit(&dict_sys->mutex); /* The MySQL optimizer seems to assume in a left join that n_rows @@ -14293,10 +14291,27 @@ ha_innobase::info_low( ib_push_frm_error(m_user_thd, ib_table, table, num_innodb_index, true); } - if (!(flag & HA_STATUS_NO_LOCK)) { - dict_table_stats_lock(ib_table, RW_S_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++) { @@ -14374,25 +14389,6 @@ ha_innobase::info_low( key->rec_per_key[j] = rec_per_key_int; } } - - if (!(flag & HA_STATUS_NO_LOCK)) { - dict_table_stats_unlock(ib_table, RW_S_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) { diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index d3e951ce5a0..d8cb0b67ab5 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6270,38 +6270,43 @@ i_s_dict_fill_sys_tablestats( OK(field_store_string(fields[SYS_TABLESTATS_NAME], table->name.m_name)); - dict_table_stats_lock(table, RW_S_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)); + } } - dict_table_stats_unlock(table, RW_S_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/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 5c94c005e4e..c6c934c76c4 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -1447,7 +1447,7 @@ ibuf_dummy_index_create( dict_index_t* index; table = dict_mem_table_create("IBUF_DUMMY", NULL, n, 0, - comp ? DICT_TF_COMPACT : 0, 0, false); + comp ? DICT_TF_COMPACT : 0, 0); index = dict_mem_index_create(table, "IBUF_DUMMY", 0, n); diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index bcf5904cd09..07ec5357822 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -219,7 +219,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)); @@ -597,7 +597,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 c6f7c846c22..c80b4063221 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/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/dict0dict.h b/storage/innobase/include/dict0dict.h index 1c34e69bbf7..3da365503cc 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1403,7 +1403,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 @@ -1468,22 +1468,6 @@ void dict_mutex_exit_for_mysql(void); /*===========================*/ -/** Lock the appropriate latch to protect a given table's statistics. -@param[in] table table whose stats to lock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_lock( - dict_table_t* table, - ulint latch_mode); - -/** Unlock the latch that has been locked by dict_table_stats_lock(). -@param[in] table table whose stats to unlock -@param[in] latch_mode RW_S_LATCH or RW_X_LATCH */ -void -dict_table_stats_unlock( - dict_table_t* table, - ulint latch_mode); - /********************************************************************//** Checks if the database name in two table names is the same. @return TRUE if same db name */ diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 244e79ae714..3b8808bf14c 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -1100,7 +1100,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 1c4292a2d38..05db1a844e4 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -302,7 +302,6 @@ before proceeds. */ @param n_v_cols number of virtual columns @param flags table flags @param flags2 table flags2 -@param init_stats_latch whether to init the stats latch @return own: table object */ dict_table_t* dict_mem_table_create( @@ -311,8 +310,7 @@ dict_mem_table_create( ulint n_cols, ulint n_v_cols, ulint flags, - ulint flags2, - bool init_stats_latch=true); + ulint flags2); /****************************************************************//** Free a table memory object. */ @@ -997,7 +995,7 @@ struct dict_index_t{ 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 @@ -1862,23 +1860,8 @@ struct dict_table_t { /*!< set of foreign key constraints which refer to this table */ dict_foreign_set referenced_set; - /** Statistics for query optimization. @{ */ - - /** Creation state of 'stats_latch'. */ - bool stats_latch_inited; - - /** 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 3853af2d409..b1c0a421dd5 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_stats_lock() 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); - dict_table_stats_lock(table, RW_X_LATCH); - if (!table->stat_initialized) { - dict_table_stats_unlock(table, RW_X_LATCH); return; } @@ -221,6 +218,4 @@ dict_stats_deinit( sizeof(index->stat_n_leaf_pages)); } #endif /* HAVE_valgrind */ - - dict_table_stats_unlock(table, RW_X_LATCH); } diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 824ec9ce931..a54e0f6a40e 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -125,7 +125,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/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 635210dd405..dc88b41c6b4 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1522,7 +1522,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. */ @@ -1892,7 +1892,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,7 +2244,7 @@ row_update_cascade_for_mysql( if (node->is_delete == PLAIN_DELETE) { /* Not protected by - dict_table_stats_lock() for + 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 9dd65a30ac1..7da9902995c 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -613,7 +613,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 f6bfacda652..f576ec6acca 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -1457,9 +1457,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 a1d0009bcc5..97641d42826 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -101,7 +101,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; |