summaryrefslogtreecommitdiff
path: root/storage/xtradb/dict/dict0dict.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/dict/dict0dict.c')
-rw-r--r--storage/xtradb/dict/dict0dict.c559
1 files changed, 387 insertions, 172 deletions
diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c
index 1d0517f5cc7..1ad540f47ab 100644
--- a/storage/xtradb/dict/dict0dict.c
+++ b/storage/xtradb/dict/dict0dict.c
@@ -53,7 +53,7 @@ UNIV_INTERN dict_index_t* dict_ind_compact;
#include "rem0cmp.h"
#include "row0merge.h"
#include "m_ctype.h" /* my_isspace() */
-#include "ha_prototypes.h" /* innobase_strcasecmp() */
+#include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
#include <ctype.h>
@@ -71,6 +71,18 @@ we need this; NOTE: a transaction which reserves this must keep book
on the mode in trx_struct::dict_operation_lock_mode */
UNIV_INTERN rw_lock_t dict_operation_lock;
+/* Keys to register rwlocks and mutexes with performance schema */
+#ifdef UNIV_PFS_RWLOCK
+UNIV_INTERN mysql_pfs_key_t dict_operation_lock_key;
+UNIV_INTERN mysql_pfs_key_t index_tree_rw_lock_key;
+UNIV_INTERN mysql_pfs_key_t dict_table_stats_latch_key;
+#endif /* UNIV_PFS_RWLOCK */
+
+#ifdef UNIV_PFS_MUTEX
+UNIV_INTERN mysql_pfs_key_t dict_sys_mutex_key;
+UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
+#endif /* UNIV_PFS_MUTEX */
+
#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
creating a table or index object */
#define DICT_POOL_PER_TABLE_HASH 512 /*!< buffer pool max size per table
@@ -81,9 +93,18 @@ UNIV_INTERN rw_lock_t dict_operation_lock;
/** Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_";
-/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */
-#define DICT_INDEX_STAT_MUTEX_SIZE 32
-static mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE];
+/** array of rw locks protecting
+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 */
+#define DICT_TABLE_STATS_LATCHES_SIZE 64
+static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
/*******************************************************************//**
Tries to find column names for the index and sets the col field of the
@@ -244,43 +265,65 @@ dict_mutex_exit_for_mysql(void)
mutex_exit(&(dict_sys->mutex));
}
-/** Get the mutex that protects index->stat_n_diff_key_vals[] */
-#define GET_INDEX_STAT_MUTEX(index) \
- (&dict_index_stat_mutex[ut_fold_dulint(index->id) \
- % DICT_INDEX_STAT_MUTEX_SIZE])
+/** Get the latch that protects the stats of a given table */
+#define GET_TABLE_STATS_LATCH(table) \
+ (&dict_table_stats_latches[ut_fold_ull(table->id) \
+ % DICT_TABLE_STATS_LATCHES_SIZE])
/**********************************************************************//**
-Lock the appropriate mutex to protect index->stat_n_diff_key_vals[].
-index->id is used to pick the right mutex and it should not change
-before dict_index_stat_mutex_exit() is called on this index. */
+Lock the appropriate latch to protect a given table's statistics.
+table->id is used to pick the corresponding latch from a global array of
+latches. */
UNIV_INTERN
void
-dict_index_stat_mutex_enter(
-/*========================*/
- const dict_index_t* index) /*!< in: index */
+dict_table_stats_lock(
+/*==================*/
+ const dict_table_t* table, /*!< in: table */
+ ulint latch_mode) /*!< in: RW_S_LATCH or
+ RW_X_LATCH */
{
- ut_ad(index != NULL);
- ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
- ut_ad(index->cached);
- ut_ad(!index->to_be_dropped);
+ ut_ad(table != NULL);
+ ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
- mutex_enter(GET_INDEX_STAT_MUTEX(index));
+ switch (latch_mode) {
+ case RW_S_LATCH:
+ rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
+ break;
+ case RW_X_LATCH:
+ rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
+ break;
+ case RW_NO_LATCH:
+ /* fall through */
+ default:
+ ut_error;
+ }
}
/**********************************************************************//**
-Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
+Unlock the latch that has been locked by dict_table_stats_lock() */
UNIV_INTERN
void
-dict_index_stat_mutex_exit(
-/*=======================*/
- const dict_index_t* index) /*!< in: index */
+dict_table_stats_unlock(
+/*====================*/
+ const dict_table_t* table, /*!< in: table */
+ ulint latch_mode) /*!< in: RW_S_LATCH or
+ RW_X_LATCH */
{
- ut_ad(index != NULL);
- ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
- ut_ad(index->cached);
- ut_ad(!index->to_be_dropped);
+ ut_ad(table != NULL);
+ ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
- mutex_exit(GET_INDEX_STAT_MUTEX(index));
+ switch (latch_mode) {
+ case RW_S_LATCH:
+ rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
+ break;
+ case RW_X_LATCH:
+ rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
+ break;
+ case RW_NO_LATCH:
+ /* fall through */
+ default:
+ ut_error;
+ }
}
/********************************************************************//**
@@ -415,14 +458,14 @@ dict_index_t*
dict_index_get_on_id_low(
/*=====================*/
dict_table_t* table, /*!< in: table */
- dulint id) /*!< in: index id */
+ index_id_t id) /*!< in: index id */
{
dict_index_t* index;
index = dict_table_get_first_index(table);
while (index) {
- if (0 == ut_dulint_cmp(id, index->id)) {
+ if (id == index->id) {
/* Found */
return(index);
@@ -564,12 +607,13 @@ UNIV_INTERN
dict_table_t*
dict_table_get_on_id(
/*=================*/
- dulint table_id, /*!< in: table id */
- trx_t* trx) /*!< in: transaction handle */
+ table_id_t table_id, /*!< in: table id */
+ trx_t* trx) /*!< in: transaction handle */
{
dict_table_t* table;
- if (trx->dict_operation_lock_mode == RW_X_LATCH) {
+ if (table_id <= DICT_FIELDS_ID
+ || trx->dict_operation_lock_mode == RW_X_LATCH) {
/* Note: An X latch implies that the transaction
already owns the dictionary mutex. */
@@ -652,7 +696,7 @@ dict_init(void)
dict_sys = mem_alloc(sizeof(dict_sys_t));
- mutex_create(&dict_sys->mutex, SYNC_DICT);
+ mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
/ (DICT_POOL_PER_TABLE_HASH
@@ -664,15 +708,18 @@ dict_init(void)
UT_LIST_INIT(dict_sys->table_LRU);
- rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
+ rw_lock_create(dict_operation_lock_key,
+ &dict_operation_lock, SYNC_DICT_OPERATION);
dict_foreign_err_file = os_file_create_tmpfile();
ut_a(dict_foreign_err_file);
- mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
+ mutex_create(dict_foreign_err_mutex_key,
+ &dict_foreign_err_mutex, SYNC_ANY_LATCH);
- for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
- mutex_create(&dict_index_stat_mutex[i], SYNC_INDEX_TREE);
+ for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
+ rw_lock_create(dict_table_stats_latch_key,
+ &dict_table_stats_latches[i], SYNC_INDEX_TREE);
}
}
@@ -704,13 +751,12 @@ dict_table_get(
mutex_exit(&(dict_sys->mutex));
- if (table != NULL) {
- if (!table->stat_initialized && !table->is_corrupt) {
- /* If table->ibd_file_missing == TRUE, this will
- print an error message and return without doing
- anything. */
- dict_update_statistics(table, FALSE);
- }
+ if (table != NULL && !table->is_corrupt) {
+ /* If table->ibd_file_missing == TRUE, this will
+ print an error message and return without doing
+ anything. */
+ dict_update_statistics(table, TRUE /* only update stats
+ if they have not been initialized */, FALSE);
}
return(table);
@@ -788,7 +834,7 @@ dict_table_add_to_cache(
table->cached = TRUE;
fold = ut_fold_string(table->name);
- id_fold = ut_fold_dulint(table->id);
+ id_fold = ut_fold_ull(table->id);
row_len = 0;
for (i = 0; i < table->n_def; i++) {
@@ -830,7 +876,7 @@ dict_table_add_to_cache(
dict_table_t* table2;
HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
dict_table_t*, table2, ut_ad(table2->cached),
- ut_dulint_cmp(table2->id, table->id) == 0);
+ table2->id == table->id);
ut_a(table2 == NULL);
#ifdef UNIV_DEBUG
@@ -865,7 +911,7 @@ UNIV_INTERN
dict_index_t*
dict_index_find_on_id_low(
/*======================*/
- dulint id) /*!< in: index id */
+ index_id_t id) /*!< in: index id */
{
dict_table_t* table;
dict_index_t* index;
@@ -876,7 +922,7 @@ dict_index_find_on_id_low(
index = dict_table_get_first_index(table);
while (index) {
- if (0 == ut_dulint_cmp(id, index->id)) {
+ if (id == index->id) {
/* Found */
return(index);
@@ -907,7 +953,7 @@ dict_table_rename_in_cache(
dict_foreign_t* foreign;
dict_index_t* index;
ulint fold;
- char old_name[MAX_TABLE_NAME_LEN + 1];
+ char old_name[MAX_FULL_NAME_LEN + 1];
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -919,7 +965,7 @@ dict_table_rename_in_cache(
ut_print_timestamp(stderr);
fprintf(stderr, "InnoDB: too long table name: '%s', "
"max length is %d\n", table->name,
- MAX_TABLE_NAME_LEN);
+ MAX_FULL_NAME_LEN);
ut_error;
}
@@ -969,11 +1015,11 @@ dict_table_rename_in_cache(
ut_fold_string(old_name), table);
if (strlen(new_name) > strlen(table->name)) {
- /* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid
+ /* We allocate MAX_FULL_NAME_LEN + 1 bytes here to avoid
memory fragmentation, we assume a repeated calls of
ut_realloc() with the same size do not cause fragmentation */
- ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
- table->name = ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1);
+ ut_a(strlen(new_name) <= MAX_FULL_NAME_LEN);
+ table->name = ut_realloc(table->name, MAX_FULL_NAME_LEN + 1);
}
memcpy(table->name, new_name, strlen(new_name) + 1);
@@ -1040,13 +1086,13 @@ dict_table_rename_in_cache(
/* Allocate a longer name buffer;
TODO: store buf len to save memory */
- foreign->foreign_table_name
- = mem_heap_alloc(foreign->heap,
- ut_strlen(table->name) + 1);
+ foreign->foreign_table_name = mem_heap_strdup(
+ foreign->heap, table->name);
+ dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
+ } else {
+ strcpy(foreign->foreign_table_name, table->name);
+ dict_mem_foreign_table_name_lookup_set(foreign, FALSE);
}
-
- strcpy(foreign->foreign_table_name, table->name);
-
if (strchr(foreign->id, '/')) {
ulint db_len;
char* old_id;
@@ -1112,12 +1158,14 @@ dict_table_rename_in_cache(
/* Allocate a longer name buffer;
TODO: store buf len to save memory */
- foreign->referenced_table_name = mem_heap_alloc(
- foreign->heap, strlen(table->name) + 1);
+ foreign->referenced_table_name = mem_heap_strdup(
+ foreign->heap, table->name);
+ dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
+ } else {
+ /* Use the same buffer */
+ strcpy(foreign->referenced_table_name, table->name);
+ dict_mem_referenced_table_name_lookup_set(foreign, FALSE);
}
-
- strcpy(foreign->referenced_table_name, table->name);
-
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
@@ -1132,7 +1180,7 @@ void
dict_table_change_id_in_cache(
/*==========================*/
dict_table_t* table, /*!< in/out: table object already in cache */
- dulint new_id) /*!< in: new id to set */
+ table_id_t new_id) /*!< in: new id to set */
{
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -1141,12 +1189,12 @@ dict_table_change_id_in_cache(
/* Remove the table from the hash table of id's */
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
- ut_fold_dulint(table->id), table);
+ ut_fold_ull(table->id), table);
table->id = new_id;
/* Add the table back to the hash table */
HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
- ut_fold_dulint(table->id), table);
+ ut_fold_ull(table->id), table);
}
/**********************************************************************//**
@@ -1202,7 +1250,7 @@ dict_table_remove_from_cache(
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
ut_fold_string(table->name), table);
HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
- ut_fold_dulint(table->id), table);
+ ut_fold_ull(table->id), table);
/* Remove table from LRU list of tables */
UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
@@ -1367,36 +1415,63 @@ dict_index_too_big_for_undo(
ulint fixed_size
= dict_col_get_fixed_size(col,
dict_table_is_comp(table));
+ ulint max_prefix
+ = col->max_prefix;
if (fixed_size) {
/* Fixed-size columns are stored locally. */
max_size = fixed_size;
} else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
/* Short columns are stored locally. */
- } else if (!col->ord_part) {
+ } else if (!col->ord_part
+ || (col->max_prefix
+ < (ulint) DICT_MAX_FIELD_LEN_BY_FORMAT(table))) {
/* See if col->ord_part would be set
- because of new_index. */
+ because of new_index. Also check if the new
+ index could have longer prefix on columns
+ that already had ord_part set */
ulint j;
for (j = 0; j < new_index->n_uniq; j++) {
if (dict_index_get_nth_col(
new_index, j) == col) {
+ const dict_field_t* field
+ = dict_index_get_nth_field(
+ new_index, j);
+
+ if (field->prefix_len
+ > col->max_prefix) {
+ max_prefix =
+ field->prefix_len;
+ }
goto is_ord_part;
}
}
+ if (col->ord_part) {
+ goto is_ord_part;
+ }
+
/* This is not an ordering column in any index.
Thus, it can be stored completely externally. */
max_size = BTR_EXTERN_FIELD_REF_SIZE;
} else {
+ ulint max_field_len;
is_ord_part:
+ max_field_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
+
/* This is an ordering column in some index.
A long enough prefix must be written to the
undo log. See trx_undo_page_fetch_ext(). */
+ max_size = ut_min(max_size, max_field_len);
+
+ /* We only store the needed prefix length in undo log */
+ if (max_prefix) {
+ ut_ad(dict_table_get_format(table)
+ >= DICT_TF_FORMAT_ZIP);
- if (max_size > REC_MAX_INDEX_COL_LEN) {
- max_size = REC_MAX_INDEX_COL_LEN;
+ max_size = ut_min(max_prefix, max_size);
}
max_size += BTR_EXTERN_FIELD_REF_SIZE;
@@ -1650,15 +1725,16 @@ too_big:
/* In dtuple_convert_big_rec(), variable-length columns
that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
may be chosen for external storage. If the column appears
- in an ordering column of an index, a longer prefix of
- REC_MAX_INDEX_COL_LEN will be copied to the undo log
- by trx_undo_page_report_modify() and
+ in an ordering column of an index, a longer prefix determined
+ by dict_max_field_len_store_undo() will be copied to the undo
+ log by trx_undo_page_report_modify() and
trx_undo_page_fetch_ext(). It suffices to check the
capacity of the undo log whenever new_index includes
a column prefix on a column that may be stored externally. */
if (field->prefix_len /* prefix index */
- && !col->ord_part /* not yet ordering column */
+ && (!col->ord_part /* not yet ordering column */
+ || field->prefix_len > col->max_prefix)
&& !dict_col_get_fixed_size(col, TRUE) /* variable-length */
&& dict_col_get_max_size(col)
> BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
@@ -1675,11 +1751,17 @@ too_big:
}
undo_size_ok:
- /* Flag the ordering columns */
+ /* Flag the ordering columns and also set column max_prefix */
for (i = 0; i < n_ord; i++) {
+ const dict_field_t* field
+ = dict_index_get_nth_field(new_index, i);
+
+ field->col->ord_part = 1;
- dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
+ if (field->prefix_len > field->col->max_prefix) {
+ field->col->max_prefix = field->prefix_len;
+ }
}
/* Add the new index as the last index for the table */
@@ -1694,7 +1776,8 @@ undo_size_ok:
new_index->stat_n_leaf_pages = 1;
new_index->page = page_no;
- rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
+ rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
+ SYNC_INDEX_TREE);
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
@@ -1702,6 +1785,12 @@ undo_size_ok:
new_index->heap,
(1 + dict_index_get_n_unique(new_index))
* sizeof(ib_int64_t));
+
+ new_index->stat_n_non_null_key_vals = mem_heap_zalloc(
+ new_index->heap,
+ (1 + dict_index_get_n_unique(new_index))
+ * sizeof(*new_index->stat_n_non_null_key_vals));
+
/* Give some sensible values to stat_n_... in case we do
not calculate statistics quickly enough */
@@ -1756,7 +1845,7 @@ dict_index_remove_from_cache(
zero. */
for (;;) {
- ulint ref_count = btr_search_info_get_ref_count(info);
+ ulint ref_count = btr_search_info_get_ref_count(info, index->id);
if (ref_count == 0) {
break;
}
@@ -1880,14 +1969,14 @@ dict_index_add_col(
variable-length fields, so that the extern flag can be embedded in
the length word. */
- if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
+ if (field->fixed_len > DICT_MAX_FIXED_COL_LEN) {
field->fixed_len = 0;
}
-#if DICT_MAX_INDEX_COL_LEN != 768
+#if DICT_MAX_FIXED_COL_LEN != 768
/* The comparison limit above must be constant. If it were
changed, the disk format of some fixed-length columns would
change, which would be a disaster. */
-# error "DICT_MAX_INDEX_COL_LEN != 768"
+# error "DICT_MAX_FIXED_COL_LEN != 768"
#endif
if (!(col->prtype & DATA_NOT_NULL)) {
@@ -2526,8 +2615,7 @@ dict_table_get_index_by_max_id(
/* We found a matching index, select
the index with the higher id*/
- if (!found
- || ut_dulint_cmp(index->id, found->id) > 0) {
+ if (!found || index->id > found->id) {
found = index;
}
@@ -2606,10 +2694,10 @@ dict_foreign_add_to_cache(
ut_ad(mutex_own(&(dict_sys->mutex)));
for_table = dict_table_check_if_in_cache_low(
- foreign->foreign_table_name);
+ foreign->foreign_table_name_lookup);
ref_table = dict_table_check_if_in_cache_low(
- foreign->referenced_table_name);
+ foreign->referenced_table_name_lookup);
ut_a(for_table || ref_table);
if (for_table) {
@@ -2726,7 +2814,7 @@ dict_scan_to(
quote = '\0';
} else if (quote) {
/* Within quotes: do nothing. */
- } else if (*ptr == '`' || *ptr == '"') {
+ } else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
/* Starting quote: remember the quote character. */
quote = *ptr;
} else {
@@ -3038,19 +3126,25 @@ dict_scan_table_name(
memcpy(ref, database_name, database_name_len);
ref[database_name_len] = '/';
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
-#ifndef __WIN__
- if (srv_lower_case_table_names) {
-#endif /* !__WIN__ */
- /* The table name is always put to lower case on Windows. */
+
+ /* Values; 0 = Store and compare as given; case sensitive
+ 1 = Store and compare in lower; case insensitive
+ 2 = Store as given, compare in lower; case semi-sensitive */
+ if (innobase_get_lower_case_table_names() == 2) {
innobase_casedn_str(ref);
-#ifndef __WIN__
+ *table = dict_table_get_low(ref);
+ memcpy(ref, database_name, database_name_len);
+ ref[database_name_len] = '/';
+ memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
+ } else {
+ if (innobase_get_lower_case_table_names() == 1) {
+ innobase_casedn_str(ref);
+ }
+ *table = dict_table_get_low(ref);
}
-#endif /* !__WIN__ */
*success = TRUE;
*ref_name = ref;
- *table = dict_table_get_low(ref);
-
return(ptr);
}
@@ -3506,7 +3600,7 @@ col_loop1:
start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
- return(DB_CANNOT_ADD_CONSTRAINT);
+ return(DB_CHILD_NO_INDEX);
}
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
@@ -3539,8 +3633,10 @@ col_loop1:
}
foreign->foreign_table = table;
- foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
- table->name);
+ foreign->foreign_table_name = mem_heap_strdup(
+ foreign->heap, table->name);
+ dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
+
foreign->foreign_index = index;
foreign->n_fields = (unsigned int) i;
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
@@ -3787,7 +3883,7 @@ try_find_index:
start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
- return(DB_CANNOT_ADD_CONSTRAINT);
+ return(DB_PARENT_NO_INDEX);
}
} else {
ut_a(trx->check_foreigns == FALSE);
@@ -3797,8 +3893,9 @@ try_find_index:
foreign->referenced_index = index;
foreign->referenced_table = referenced_table;
- foreign->referenced_table_name
- = mem_heap_strdup(foreign->heap, referenced_table_name);
+ foreign->referenced_table_name = mem_heap_strdup(
+ foreign->heap, referenced_table_name);
+ dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
i * sizeof(void*));
@@ -4015,7 +4112,7 @@ UNIV_INTERN
dict_index_t*
dict_index_get_if_in_cache_low(
/*===========================*/
- dulint index_id) /*!< in: index id */
+ index_id_t index_id) /*!< in: index id */
{
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -4030,7 +4127,7 @@ UNIV_INTERN
dict_index_t*
dict_index_get_if_in_cache(
/*=======================*/
- dulint index_id) /*!< in: index id */
+ index_id_t index_id) /*!< in: index id */
{
dict_index_t* index;
@@ -4301,15 +4398,18 @@ dict_reload_statistics(
ulint key_cols;
ulint n_cols;
const rec_t* rec;
+ ulint n_fields;
const byte* field;
ulint len;
ib_int64_t* stat_n_diff_key_vals_tmp;
+ ib_int64_t* stat_n_non_null_key_vals_tmp;
byte* buf;
ulint i;
mtr_t mtr;
n_cols = dict_index_get_n_unique(index);
stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
+ stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
sys_stats = dict_sys->sys_stats;
sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
@@ -4332,11 +4432,11 @@ dict_reload_statistics(
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur)
- || ut_dulint_cmp(mach_read_from_8(rec_get_nth_field_old(rec, 0, &len)),
- index->id)) {
+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
+ != index->id) {
/* not found: even 1 if not found should not be alowed */
fprintf(stderr, "InnoDB: Warning: stats for %s/%s (%lu/%lu)"
- " not fonund in SYS_STATS\n",
+ " not found in SYS_STATS\n",
index->table_name, index->name, i, n_cols);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -4345,9 +4445,13 @@ dict_reload_statistics(
}
if (rec_get_deleted_flag(rec, 0)) {
+ /* don't count */
+ i--;
goto next_rec;
}
+ n_fields = rec_get_n_fields_old(rec);
+
field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
@@ -4358,7 +4462,22 @@ dict_reload_statistics(
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
ut_a(len == 8);
- stat_n_diff_key_vals_tmp[i] = ut_conv_dulint_to_longlong(mach_read_from_8(field));
+ stat_n_diff_key_vals_tmp[i] = mach_read_from_8(field);
+
+ if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
+ ut_a(len == 8);
+
+ stat_n_non_null_key_vals_tmp[i] = mach_read_from_8(field);
+ } else {
+ /* not enough fields: should be older */
+ fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
+ " in SYS_STATS seems older format. "
+ "Please execute ANALYZE TABLE for it.\n",
+ index->table_name, index->name, i, n_cols);
+
+ stat_n_non_null_key_vals_tmp[i] = ((ib_int64_t)(-1));
+ }
next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
@@ -4366,11 +4485,15 @@ next_rec:
btr_pcur_close(&pcur);
mtr_commit(&mtr);
- dict_index_stat_mutex_enter(index);
for (i = 0; i <= n_cols; i++) {
index->stat_n_diff_key_vals[i] = stat_n_diff_key_vals_tmp[i];
+ if (stat_n_non_null_key_vals_tmp[i] == ((ib_int64_t)(-1))) {
+ /* approximate value */
+ index->stat_n_non_null_key_vals[i] = stat_n_diff_key_vals_tmp[n_cols];
+ } else {
+ index->stat_n_non_null_key_vals[i] = stat_n_non_null_key_vals_tmp[i];
+ }
}
- dict_index_stat_mutex_exit(index);
}
/*===========================================*/
@@ -4414,21 +4537,23 @@ dict_store_statistics(
ulint n_cols;
ulint rests;
const rec_t* rec;
+ ulint n_fields;
const byte* field;
ulint len;
ib_int64_t* stat_n_diff_key_vals_tmp;
+ ib_int64_t* stat_n_non_null_key_vals_tmp;
byte* buf;
ulint i;
mtr_t mtr;
n_cols = dict_index_get_n_unique(index);
stat_n_diff_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
+ stat_n_non_null_key_vals_tmp = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
- dict_index_stat_mutex_enter(index);
for (i = 0; i <= n_cols; i++) {
stat_n_diff_key_vals_tmp[i] = index->stat_n_diff_key_vals[i];
+ stat_n_non_null_key_vals_tmp[i] = index->stat_n_non_null_key_vals[i];
}
- dict_index_stat_mutex_exit(index);
sys_stats = dict_sys->sys_stats;
sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
@@ -4452,15 +4577,29 @@ dict_store_statistics(
rec = btr_pcur_get_rec(&pcur);
if (!btr_pcur_is_on_user_rec(&pcur)
- || ut_dulint_cmp(mach_read_from_8(rec_get_nth_field_old(rec, 0, &len)),
- index->id)) {
+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
+ != index->id) {
/* not found */
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
+
+
break;
}
+ btr_pcur_store_position(&pcur, &mtr);
+
if (rec_get_deleted_flag(rec, 0)) {
+ /* don't count */
+ i--;
+ goto next_rec;
+ }
+
+ n_fields = rec_get_n_fields_old(rec);
+
+ if (n_fields <= DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
+ /* not update for the older smaller format */
+ fprintf(stderr, "InnoDB: Notice: stats for %s/%s (%lu/%lu)"
+ " in SYS_STATS seems older format. Please ANALYZE TABLE it.\n",
+ index->table_name, index->name, i, n_cols);
goto next_rec;
}
@@ -4472,14 +4611,20 @@ dict_store_statistics(
field = rec_get_nth_field_old(rec, DICT_SYS_STATS_DIFF_VALS_FIELD, &len);
ut_a(len == 8);
- mlog_write_dulint((byte*)field,
- ut_dulint_create((ulint) (stat_n_diff_key_vals_tmp[key_cols] >> 32),
- (ulint) stat_n_diff_key_vals_tmp[key_cols] & 0xFFFFFFFF),
- &mtr);
+ mlog_write_ull((byte*)field, stat_n_diff_key_vals_tmp[key_cols], &mtr);
+
+ field = rec_get_nth_field_old(rec, DICT_SYS_STATS_NON_NULL_VALS_FIELD, &len);
+ ut_a(len == 8);
+
+ mlog_write_ull((byte*)field, stat_n_non_null_key_vals_tmp[key_cols], &mtr);
rests--;
next_rec:
+ mtr_commit(&mtr);
+ mtr_start(&mtr);
+ btr_pcur_restore_position(BTR_MODIFY_LEAF, &pcur, &mtr);
+
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
btr_pcur_close(&pcur);
@@ -4504,12 +4649,13 @@ Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
UNIV_INTERN
void
-dict_update_statistics_low(
-/*=======================*/
+dict_update_statistics(
+/*===================*/
dict_table_t* table, /*!< in/out: table */
- ibool has_dict_mutex __attribute__((unused)),
- /*!< in: TRUE if the caller has the
- dictionary mutex */
+ ibool only_calc_if_missing_stats,/*!< in: only
+ update/recalc the stats if they have
+ not been initialized yet, otherwise
+ do nothing */
ibool sync) /*!< in: TRUE if must update SYS_STATS */
{
dict_index_t* index;
@@ -4528,15 +4674,19 @@ dict_update_statistics_low(
}
if (srv_use_sys_stats_table && !((table->flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) && !sync) {
+ dict_table_stats_lock(table, RW_X_LATCH);
+
/* reload statistics from SYS_STATS table */
if (dict_reload_statistics(table, &sum_of_index_sizes)) {
/* success */
#ifdef UNIV_DEBUG
- fprintf(stderr, "InnoDB: DEBUG: reload_statistics is scceeded for %s.\n",
+ fprintf(stderr, "InnoDB: DEBUG: reload_statistics succeeded for %s.\n",
table->name);
#endif
goto end;
}
+
+ dict_table_stats_unlock(table, RW_X_LATCH);
}
#ifdef UNIV_DEBUG
fprintf(stderr, "InnoDB: DEBUG: update_statistics for %s.\n",
@@ -4555,17 +4705,26 @@ dict_update_statistics_low(
return;
}
- do {
- if (table->is_corrupt) {
- ut_a(srv_pass_corrupt_table);
- return;
- }
+ dict_table_stats_lock(table, RW_X_LATCH);
+ if (only_calc_if_missing_stats && table->stat_initialized) {
+ dict_table_stats_unlock(table, RW_X_LATCH);
+ return;
+ }
+
+ do {
if (UNIV_LIKELY
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
&& dict_index_is_clust(index)))) {
ulint size;
+
+ if (table->is_corrupt) {
+ ut_a(srv_pass_corrupt_table);
+ dict_table_stats_unlock(table, RW_X_LATCH);
+ return;
+ }
+
size = btr_get_size(index, BTR_TOTAL_SIZE);
index->stat_index_size = size;
@@ -4597,6 +4756,10 @@ dict_update_statistics_low(
for (i = dict_index_get_n_unique(index); i; ) {
index->stat_n_diff_key_vals[i--] = 1;
}
+
+ memset(index->stat_n_non_null_key_vals, 0,
+ (1 + dict_index_get_n_unique(index))
+ * sizeof(*index->stat_n_non_null_key_vals));
}
index = dict_table_get_next_index(index);
@@ -4609,13 +4772,9 @@ dict_update_statistics_low(
end:
index = dict_table_get_first_index(table);
- dict_index_stat_mutex_enter(index);
-
table->stat_n_rows = index->stat_n_diff_key_vals[
dict_index_get_n_unique(index)];
- dict_index_stat_mutex_exit(index);
-
table->stat_clustered_index_size = index->stat_index_size;
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
@@ -4624,19 +4783,80 @@ end:
table->stat_initialized = TRUE;
table->stat_modified_counter = 0;
+
+ dict_table_stats_unlock(table, RW_X_LATCH);
}
/*********************************************************************//**
-Calculates new estimates for table and index statistics. The statistics
-are used in query optimization. */
+*/
UNIV_INTERN
-void
-dict_update_statistics(
-/*===================*/
- dict_table_t* table, /*!< in/out: table */
- ibool sync)
+ibool
+dict_is_older_statistics(
+/*=====================*/
+ dict_index_t* index)
{
- dict_update_statistics_low(table, FALSE, sync);
+ mem_heap_t* heap;
+ dict_table_t* sys_stats;
+ dict_index_t* sys_index;
+ btr_pcur_t pcur;
+ dtuple_t* tuple;
+ dfield_t* dfield;
+ const rec_t* rec;
+ ulint n_fields;
+ ulint len;
+ byte* buf;
+ mtr_t mtr;
+
+ heap = mem_heap_create(100);
+
+ sys_stats = dict_sys->sys_stats;
+ sys_index = UT_LIST_GET_FIRST(sys_stats->indexes);
+ ut_a(!dict_table_is_comp(sys_stats));
+
+ tuple = dtuple_create(heap, 1);
+ dfield = dtuple_get_nth_field(tuple, 0);
+
+ buf = mem_heap_alloc(heap, 8);
+ mach_write_to_8(buf, index->id);
+
+ dfield_set_data(dfield, buf, 8);
+ dict_index_copy_types(tuple, sys_index, 1);
+
+ mtr_start(&mtr);
+
+ btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
+ BTR_SEARCH_LEAF, &pcur, &mtr);
+
+next_rec:
+ rec = btr_pcur_get_rec(&pcur);
+
+ if (!btr_pcur_is_on_user_rec(&pcur)
+ || mach_read_from_8(rec_get_nth_field_old(rec, 0, &len))
+ != index->id) {
+ /* not found */
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+ /* no statistics == not older statistics */
+ return(FALSE);
+ }
+
+ if (rec_get_deleted_flag(rec, 0)) {
+ btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+ goto next_rec;
+ }
+
+ n_fields = rec_get_n_fields_old(rec);
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+
+ if (n_fields > DICT_SYS_STATS_NON_NULL_VALS_FIELD) {
+ return(FALSE);
+ } else {
+ return(TRUE);
+ }
}
/**********************************************************************//**
@@ -4717,16 +4937,17 @@ dict_table_print_low(
ut_ad(mutex_own(&(dict_sys->mutex)));
if (srv_stats_auto_update)
- dict_update_statistics_low(table, TRUE, FALSE);
+ dict_update_statistics(table, FALSE /* update even if initialized */, FALSE);
+
+ dict_table_stats_lock(table, RW_S_LATCH);
fprintf(stderr,
"--------------------------------------\n"
- "TABLE: name %s, id %lu %lu, flags %lx, columns %lu,"
+ "TABLE: name %s, id %llu, flags %lx, columns %lu,"
" indexes %lu, appr.rows %lu\n"
" COLUMNS: ",
table->name,
- (ulong) ut_dulint_get_high(table->id),
- (ulong) ut_dulint_get_low(table->id),
+ (ullint) table->id,
(ulong) table->flags,
(ulong) table->n_cols,
(ulong) UT_LIST_GET_LEN(table->indexes),
@@ -4746,6 +4967,8 @@ dict_table_print_low(
index = UT_LIST_GET_NEXT(indexes, index);
}
+ dict_table_stats_unlock(table, RW_S_LATCH);
+
foreign = UT_LIST_GET_FIRST(table->foreign_list);
while (foreign != NULL) {
@@ -4791,12 +5014,9 @@ dict_index_print_low(
{
ib_int64_t n_vals;
ulint i;
- const char* type_string;
ut_ad(mutex_own(&(dict_sys->mutex)));
- dict_index_stat_mutex_enter(index);
-
if (index->n_user_defined_cols > 0) {
n_vals = index->stat_n_diff_key_vals[
index->n_user_defined_cols];
@@ -4804,25 +5024,14 @@ dict_index_print_low(
n_vals = index->stat_n_diff_key_vals[1];
}
- dict_index_stat_mutex_exit(index);
-
- if (dict_index_is_clust(index)) {
- type_string = "clustered index";
- } else if (dict_index_is_unique(index)) {
- type_string = "unique index";
- } else {
- type_string = "secondary index";
- }
-
fprintf(stderr,
- " INDEX: name %s, id %lu %lu, fields %lu/%lu,"
+ " INDEX: name %s, id %llu, fields %lu/%lu,"
" uniq %lu, type %lu\n"
" root page %lu, appr.key vals %lu,"
" leaf pages %lu, size pages %lu\n"
" FIELDS: ",
index->name,
- (ulong) ut_dulint_get_high(index->id),
- (ulong) ut_dulint_get_low(index->id),
+ (ullint) index->id,
(ulong) index->n_user_defined_cols,
(ulong) index->n_fields,
(ulong) index->n_uniq,
@@ -4909,8 +5118,8 @@ dict_print_info_on_foreign_key_in_create_format(
fputs(") REFERENCES ", file);
- if (dict_tables_have_same_db(foreign->foreign_table_name,
- foreign->referenced_table_name)) {
+ if (dict_tables_have_same_db(foreign->foreign_table_name_lookup,
+ foreign->referenced_table_name_lookup)) {
/* Do not print the database name of the referenced table */
ut_print_name(file, trx, TRUE,
dict_remove_db_name(
@@ -5157,7 +5366,8 @@ void
dict_table_replace_index_in_foreign_list(
/*=====================================*/
dict_table_t* table, /*!< in/out: table */
- dict_index_t* index) /*!< in: index to be replaced */
+ dict_index_t* index, /*!< in: index to be replaced */
+ const trx_t* trx) /*!< in: transaction handle */
{
dict_foreign_t* foreign;
@@ -5168,7 +5378,13 @@ dict_table_replace_index_in_foreign_list(
if (foreign->foreign_index == index) {
dict_index_t* new_index
= dict_foreign_find_equiv_index(foreign);
- ut_a(new_index);
+
+ /* There must exist an alternative index if
+ check_foreigns (FOREIGN_KEY_CHECKS) is on,
+ since ha_innobase::prepare_drop_index had done
+ the check before we reach here. */
+
+ ut_a(new_index || !trx->check_foreigns);
foreign->foreign_index = new_index;
}
@@ -5194,8 +5410,7 @@ dict_table_get_index_on_name_and_min_id(
while (index != NULL) {
if (ut_strcmp(index->name, name) == 0) {
- if (!min_index
- || ut_dulint_cmp(index->id, min_index->id) < 0) {
+ if (!min_index || index->id < min_index->id) {
min_index = index;
}
@@ -5302,8 +5517,8 @@ dict_close(void)
mem_free(dict_sys);
dict_sys = NULL;
- for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
- mutex_free(&dict_index_stat_mutex[i]);
+ for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
+ rw_lock_free(&dict_table_stats_latches[i]);
}
}