1
1
/*****************************************************************************
3
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
3
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
92
90
/** Identifies generated InnoDB foreign key names */
93
91
static char dict_ibfk[] = "_ibfk_";
95
/** array of rw locks protecting
96
dict_table_t::stat_initialized
97
dict_table_t::stat_n_rows (*)
98
dict_table_t::stat_clustered_index_size
99
dict_table_t::stat_sum_of_other_index_sizes
100
dict_table_t::stat_modified_counter (*)
101
dict_table_t::indexes*::stat_n_diff_key_vals[]
102
dict_table_t::indexes*::stat_index_size
103
dict_table_t::indexes*::stat_n_leaf_pages
104
(*) those are not always protected for performance reasons */
105
#define DICT_TABLE_STATS_LATCHES_SIZE 64
106
static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
93
/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */
94
#define DICT_INDEX_STAT_MUTEX_SIZE 32
95
static mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE];
108
97
/*******************************************************************//**
109
98
Tries to find column names for the index and sets the col field of the
264
253
mutex_exit(&(dict_sys->mutex));
267
/** Get the latch that protects the stats of a given table */
268
#define GET_TABLE_STATS_LATCH(table) \
269
(&dict_table_stats_latches[ut_fold_ull(table->id) \
270
% DICT_TABLE_STATS_LATCHES_SIZE])
256
/** Get the mutex that protects index->stat_n_diff_key_vals[] */
257
#define GET_INDEX_STAT_MUTEX(index) \
258
(&dict_index_stat_mutex[ut_fold_ull(index->id) \
259
% DICT_INDEX_STAT_MUTEX_SIZE])
272
261
/**********************************************************************//**
273
Lock the appropriate latch to protect a given table's statistics.
274
table->id is used to pick the corresponding latch from a global array of
262
Lock the appropriate mutex to protect index->stat_n_diff_key_vals[].
263
index->id is used to pick the right mutex and it should not change
264
before dict_index_stat_mutex_exit() is called on this index. */
278
dict_table_stats_lock(
279
/*==================*/
280
const dict_table_t* table, /*!< in: table */
281
ulint latch_mode) /*!< in: RW_S_LATCH or
267
dict_index_stat_mutex_enter(
268
/*========================*/
269
const dict_index_t* index) /*!< in: index */
284
ut_ad(table != NULL);
285
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
271
ut_ad(index != NULL);
272
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
273
ut_ad(index->cached);
274
ut_ad(!index->to_be_dropped);
287
switch (latch_mode) {
289
rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
292
rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
276
mutex_enter(GET_INDEX_STAT_MUTEX(index));
301
279
/**********************************************************************//**
302
Unlock the latch that has been locked by dict_table_stats_lock() */
280
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
305
dict_table_stats_unlock(
306
/*====================*/
307
const dict_table_t* table, /*!< in: table */
308
ulint latch_mode) /*!< in: RW_S_LATCH or
283
dict_index_stat_mutex_exit(
284
/*=======================*/
285
const dict_index_t* index) /*!< in: index */
311
ut_ad(table != NULL);
312
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
287
ut_ad(index != NULL);
288
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
289
ut_ad(index->cached);
290
ut_ad(!index->to_be_dropped);
314
switch (latch_mode) {
316
rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
319
rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
292
mutex_exit(GET_INDEX_STAT_MUTEX(index));
328
295
/********************************************************************//**
713
681
mutex_create(dict_foreign_err_mutex_key,
714
682
&dict_foreign_err_mutex, SYNC_ANY_LATCH);
716
for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
717
rw_lock_create(PFS_NOT_INSTRUMENTED,
718
&dict_table_stats_latches[i], SYNC_INDEX_TREE);
684
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
685
mutex_create(PFS_NOT_INSTRUMENTED,
686
&dict_index_stat_mutex[i], SYNC_INDEX_TREE);
722
690
/**********************************************************************//**
746
714
mutex_exit(&(dict_sys->mutex));
748
716
if (table != NULL) {
749
/* If table->ibd_file_missing == TRUE, this will
750
print an error message and return without doing
752
dict_update_statistics(table, TRUE /* only update stats
753
if they have not been initialized */);
717
if (!table->stat_initialized) {
718
/* If table->ibd_file_missing == TRUE, this will
719
print an error message and return without doing
721
dict_update_statistics(table);
1013
982
memory fragmentation, we assume a repeated calls of
1014
983
ut_realloc() with the same size do not cause fragmentation */
1015
984
ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
1016
table->name = static_cast<char *>(ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1));
985
table->name = ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1);
1018
987
memcpy(table->name, new_name, strlen(new_name) + 1);
1081
1050
TODO: store buf len to save memory */
1083
1052
foreign->foreign_table_name
1084
= static_cast<char *>(mem_heap_alloc(foreign->heap,
1085
ut_strlen(table->name) + 1));
1053
= mem_heap_alloc(foreign->heap,
1054
ut_strlen(table->name) + 1);
1088
1057
strcpy(foreign->foreign_table_name, table->name);
1124
1093
if (dict_get_db_name_len(table->name)
1125
1094
> dict_get_db_name_len(foreign->id)) {
1127
foreign->id = static_cast<char *>(mem_heap_alloc(
1096
foreign->id = mem_heap_alloc(
1129
db_len + strlen(old_id) + 1));
1098
db_len + strlen(old_id) + 1);
1132
1101
/* Replace the database prefix in id with the
1152
1121
/* Allocate a longer name buffer;
1153
1122
TODO: store buf len to save memory */
1155
foreign->referenced_table_name = static_cast<char *>(mem_heap_alloc(
1156
foreign->heap, strlen(table->name) + 1));
1124
foreign->referenced_table_name = mem_heap_alloc(
1125
foreign->heap, strlen(table->name) + 1);
1159
1128
strcpy(foreign->referenced_table_name, table->name);
1682
1651
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1684
new_index->stat_n_diff_key_vals = static_cast<ib_int64_t *>(mem_heap_alloc(
1653
new_index->stat_n_diff_key_vals = mem_heap_alloc(
1685
1654
new_index->heap,
1686
1655
(1 + dict_index_get_n_unique(new_index))
1687
* sizeof(ib_int64_t)));
1656
* sizeof(ib_int64_t));
1688
1657
/* Give some sensible values to stat_n_... in case we do
1689
1658
not calculate statistics quickly enough */
2067
2036
/* Remember the table columns already contained in new_index */
2068
void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
2069
indexed = static_cast<unsigned long *>(indexed_ptr);
2037
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
2071
2039
/* Mark the table columns already contained in new_index */
2072
2040
for (i = 0; i < new_index->n_def; i++) {
2150
2118
dict_index_copy(new_index, index, table, 0, index->n_fields);
2152
2120
/* Remember the table columns already contained in new_index */
2153
void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
2154
indexed = static_cast<unsigned long *>(indexed_ptr);
2121
indexed = mem_zalloc(table->n_cols * sizeof *indexed);
2156
2123
/* Mark the table columns already contained in new_index */
2157
2124
for (i = 0; i < new_index->n_def; i++) {
2861
2828
/* Convert the identifier from connection character set
2863
2830
len = 3 * len + 1;
2864
*id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
2831
*id = dst = mem_heap_alloc(heap, len);
2866
2833
innobase_convert_from_id(cs, dst, str, len);
2867
} else if (!strncmp(str, srv_mysql50_table_name_prefix.c_str(),
2868
srv_mysql50_table_name_prefix.size())) {
2834
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2835
sizeof srv_mysql50_table_name_prefix)) {
2869
2836
/* This is a pre-5.1 table name
2870
2837
containing chars other than [A-Za-z0-9].
2871
2838
Discard the prefix and use raw UTF-8 encoding. */
2872
str += srv_mysql50_table_name_prefix.size();
2873
len -= srv_mysql50_table_name_prefix.size();
2839
str += sizeof srv_mysql50_table_name_prefix;
2840
len -= sizeof srv_mysql50_table_name_prefix;
2874
2841
goto convert_id;
2876
2843
/* Encode using filename-safe characters. */
2877
2844
len = 5 * len + 1;
2878
*id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
2845
*id = dst = mem_heap_alloc(heap, len);
2880
2847
innobase_convert_from_table_id(cs, dst, str, len);
3013
2980
table_name_len = strlen(table_name);
3015
2982
/* Copy database_name, '/', table_name, '\0' */
3016
ref = static_cast<char *>(mem_heap_alloc(heap, database_name_len + table_name_len + 2));
2983
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
3017
2984
memcpy(ref, database_name, database_name_len);
3018
2985
ref[database_name_len] = '/';
3019
2986
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
3485
3452
start_of_latest_foreign);
3486
3453
mutex_exit(&dict_foreign_err_mutex);
3488
return(DB_CHILD_NO_INDEX);
3455
return(DB_CANNOT_ADD_CONSTRAINT);
3490
3457
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3510
3477
db_len = dict_get_db_name_len(table->name);
3512
foreign->id = static_cast<char*>(mem_heap_alloc(
3513
foreign->heap, db_len + strlen(constraint_name) + 2));
3479
foreign->id = mem_heap_alloc(
3480
foreign->heap, db_len + strlen(constraint_name) + 2);
3515
3482
ut_memcpy(foreign->id, table->name, db_len);
3516
3483
foreign->id[db_len] = '/';
3523
3490
foreign->foreign_index = index;
3524
3491
foreign->n_fields = (unsigned int) i;
3525
foreign->foreign_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
3526
i * sizeof(void*)));
3492
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
3527
3494
for (i = 0; i < foreign->n_fields; i++) {
3528
3495
foreign->foreign_col_names[i] = mem_heap_strdup(
3779
3746
foreign->referenced_table_name
3780
3747
= mem_heap_strdup(foreign->heap, referenced_table_name);
3782
foreign->referenced_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
3783
i * sizeof(void*)));
3749
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3784
3751
for (i = 0; i < foreign->n_fields; i++) {
3785
3752
foreign->referenced_col_names[i]
3786
3753
= mem_heap_strdup(foreign->heap, column_names[i]);
3838
3805
heap = mem_heap_create(10000);
3840
3807
err = dict_create_foreign_constraints_low(
3841
trx, heap, trx->session()->charset(), str, name,
3808
trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3844
3811
mem_heap_free(heap);
3877
3844
ut_a(trx->mysql_thd);
3879
cs = trx->session()->charset();
3846
cs = innobase_get_charset(trx->mysql_thd);
3883
*constraints_to_drop = static_cast<const char **>(mem_heap_alloc(heap, 1000 * sizeof(char*)));
3850
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3885
ptr= trx->session()->getQueryStringCopy(len);
3852
ptr = innobase_get_stmt(trx->mysql_thd, &len);
3887
3854
str = dict_strip_comments(ptr, len);
4098
4065
dict_index_copy_types(tuple, index, n_unique);
4100
buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
4067
buf = mem_heap_alloc(heap, 4);
4102
4069
mach_write_to_4(buf, page_no);
4230
4197
are used in query optimization. */
4233
dict_update_statistics(
4234
/*===================*/
4200
dict_update_statistics_low(
4201
/*=======================*/
4235
4202
dict_table_t* table, /*!< in/out: table */
4236
ibool only_calc_if_missing_stats)/*!< in: only
4237
update/recalc the stats if they have
4238
not been initialized yet, otherwise
4203
ibool has_dict_mutex __attribute__((unused)))
4204
/*!< in: TRUE if the caller has the
4241
4207
dict_index_t* index;
4242
4209
ulint sum_of_index_sizes = 0;
4244
4211
if (table->ibd_file_missing) {
4223
/* If we have set a high innodb_force_recovery level, do not calculate
4224
statistics, as a badly corrupted index can cause a crash in it. */
4226
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
4256
4231
/* Find out the sizes of the indexes and how many different values
4257
4232
for the key they approximately have */
4267
dict_table_stats_lock(table, RW_X_LATCH);
4269
if (only_calc_if_missing_stats && table->stat_initialized) {
4270
dict_table_stats_unlock(table, RW_X_LATCH);
4276
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
4277
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
4278
&& dict_index_is_clust(index)))) {
4280
size = btr_get_size(index, BTR_TOTAL_SIZE);
4282
index->stat_index_size = size;
4284
sum_of_index_sizes += size;
4286
size = btr_get_size(index, BTR_N_LEAF_PAGES);
4289
/* The root node of the tree is a leaf */
4293
index->stat_n_leaf_pages = size;
4295
btr_estimate_number_of_different_key_vals(index);
4297
/* If we have set a high innodb_force_recovery
4298
level, do not calculate statistics, as a badly
4299
corrupted index can cause a crash in it.
4300
Initialize some bogus index cardinality
4301
statistics, so that the data can be queried in
4302
various means, also via secondary indexes. */
4305
sum_of_index_sizes++;
4306
index->stat_index_size = index->stat_n_leaf_pages = 1;
4308
for (i = dict_index_get_n_unique(index); i; ) {
4309
index->stat_n_diff_key_vals[i--] = 1;
4243
size = btr_get_size(index, BTR_TOTAL_SIZE);
4245
index->stat_index_size = size;
4247
sum_of_index_sizes += size;
4249
size = btr_get_size(index, BTR_N_LEAF_PAGES);
4252
/* The root node of the tree is a leaf */
4256
index->stat_n_leaf_pages = size;
4258
btr_estimate_number_of_different_key_vals(index);
4313
4260
index = dict_table_get_next_index(index);
4316
4263
index = dict_table_get_first_index(table);
4265
dict_index_stat_mutex_enter(index);
4318
4267
table->stat_n_rows = index->stat_n_diff_key_vals[
4319
4268
dict_index_get_n_unique(index)];
4270
dict_index_stat_mutex_exit(index);
4321
4272
table->stat_clustered_index_size = index->stat_index_size;
4323
4274
table->stat_sum_of_other_index_sizes = sum_of_index_sizes
4326
4277
table->stat_initialized = TRUE;
4328
4279
table->stat_modified_counter = 0;
4330
dict_table_stats_unlock(table, RW_X_LATCH);
4282
/*********************************************************************//**
4283
Calculates new estimates for table and index statistics. The statistics
4284
are used in query optimization. */
4287
dict_update_statistics(
4288
/*===================*/
4289
dict_table_t* table) /*!< in/out: table */
4291
dict_update_statistics_low(table, FALSE);
4333
4294
/**********************************************************************//**
4408
4369
ut_ad(mutex_own(&(dict_sys->mutex)));
4410
dict_update_statistics(table, FALSE /* update even if initialized */);
4412
dict_table_stats_lock(table, RW_S_LATCH);
4371
dict_update_statistics_low(table, TRUE);
4414
4373
fprintf(stderr,
4415
4374
"--------------------------------------\n"
4494
4454
n_vals = index->stat_n_diff_key_vals[1];
4457
dict_index_stat_mutex_exit(index);
4459
if (dict_index_is_clust(index)) {
4460
type_string = "clustered index";
4461
} else if (dict_index_is_unique(index)) {
4462
type_string = "unique index";
4464
type_string = "secondary index";
4497
4467
fprintf(stderr,
4498
4468
" INDEX: name %s, id %llu, fields %lu/%lu,"
4499
4469
" uniq %lu, type %lu\n"
4836
4806
dict_table_replace_index_in_foreign_list(
4837
4807
/*=====================================*/
4838
4808
dict_table_t* table, /*!< in/out: table */
4839
dict_index_t* index, /*!< in: index to be replaced */
4840
const trx_t* trx) /*!< in: transaction handle */
4809
dict_index_t* index) /*!< in: index to be replaced */
4842
4811
dict_foreign_t* foreign;
4848
4817
if (foreign->foreign_index == index) {
4849
4818
dict_index_t* new_index
4850
4819
= dict_foreign_find_equiv_index(foreign);
4852
/* There must exist an alternative index if
4853
check_foreigns (FOREIGN_KEY_CHECKS) is on,
4854
since ha_innobase::prepare_drop_index had done
4855
the check before we reach here. */
4857
ut_a(new_index || !trx->check_foreigns);
4859
4822
foreign->foreign_index = new_index;
4951
4914
for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
4952
4915
dict_table_t* table;
4954
table = static_cast<dict_table_t *>(HASH_GET_FIRST(dict_sys->table_hash, i));
4917
table = HASH_GET_FIRST(dict_sys->table_hash, i);
4956
4919
while (table) {
4957
4920
dict_table_t* prev_table = table;
4959
table = static_cast<dict_table_t *>(HASH_GET_NEXT(name_hash, prev_table));
4922
table = HASH_GET_NEXT(name_hash, prev_table);
4960
4923
#ifdef UNIV_DEBUG
4961
4924
ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);