diff options
author | Igor Babaev <igor@askmonty.org> | 2013-01-13 00:40:38 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2013-01-13 00:40:38 -0800 |
commit | 7d5c56cb410bd0363e1c66c31149a79086584bbb (patch) | |
tree | cf76debbd4fa1d761c00f5798aec2e1843185686 | |
parent | 7d9df8075e4c9392f4352e6ccd86921994f264bc (diff) | |
download | mariadb-git-7d5c56cb410bd0363e1c66c31149a79086584bbb.tar.gz |
Fixed bug mdev-4019.
The bug could cause a crash when several connections needed
persistent statistics for the same table.
Also added a missing call of set_statistics_for_table() in the code
of the function mysql_update.
-rw-r--r-- | mysql-test/r/stat_tables_par.result | 20 | ||||
-rw-r--r-- | mysql-test/r/stat_tables_par_innodb.result | 20 | ||||
-rw-r--r-- | mysql-test/t/stat_tables_par.test | 33 | ||||
-rw-r--r-- | sql/sql_base.cc | 1 | ||||
-rw-r--r-- | sql/sql_statistics.cc | 10 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 | ||||
-rw-r--r-- | sql/table.h | 1 |
7 files changed, 85 insertions, 2 deletions
diff --git a/mysql-test/r/stat_tables_par.result b/mysql-test/r/stat_tables_par.result index 76a42e993f6..a98f934fa96 100644 --- a/mysql-test/r/stat_tables_par.result +++ b/mysql-test/r/stat_tables_par.result @@ -219,4 +219,24 @@ set debug_sync='RESET'; set global use_stat_tables=@save_global_use_stat_tables; DROP DATABASE dbt3_s001; use test; +set @save_global_use_stat_tables=@@global.use_stat_tables; +set global use_stat_tables='preferably'; +set debug_sync='RESET'; +create table t1 (a int, b int, key(a)); +insert t1 values (1,1),(2,2); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +SET debug_sync='after_open_table_ignore_flush WAIT_FOR go'; +select * from information_schema.statistics where table_schema='test'; +select * from t1; +a b +1 1 +2 2 +SET DEBUG_SYNC= "now SIGNAL go"; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT +def test t1 1 test a 1 a A 2 NULL NULL YES BTREE +set debug_sync='RESET'; +drop table t1; +set global use_stat_tables=@save_global_use_stat_tables; set use_stat_tables=@save_use_stat_tables; diff --git a/mysql-test/r/stat_tables_par_innodb.result b/mysql-test/r/stat_tables_par_innodb.result index ff1a296e5af..e0c00c482a0 100644 --- a/mysql-test/r/stat_tables_par_innodb.result +++ b/mysql-test/r/stat_tables_par_innodb.result @@ -228,6 +228,26 @@ set debug_sync='RESET'; set global use_stat_tables=@save_global_use_stat_tables; DROP DATABASE dbt3_s001; use test; +set @save_global_use_stat_tables=@@global.use_stat_tables; +set global use_stat_tables='preferably'; +set debug_sync='RESET'; +create table t1 (a int, b int, key(a)); +insert t1 values (1,1),(2,2); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +SET debug_sync='after_open_table_ignore_flush WAIT_FOR go'; +select * from information_schema.statistics where table_schema='test'; +select * from t1; +a b +1 1 +2 2 +SET DEBUG_SYNC= "now SIGNAL go"; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT +def test t1 1 test a 1 a A 2 NULL NULL YES BTREE +set debug_sync='RESET'; +drop table t1; +set global use_stat_tables=@save_global_use_stat_tables; set use_stat_tables=@save_use_stat_tables; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; SET SESSION STORAGE_ENGINE=DEFAULT; diff --git a/mysql-test/t/stat_tables_par.test b/mysql-test/t/stat_tables_par.test index 57b57e3ebba..6c4e1be6e48 100644 --- a/mysql-test/t/stat_tables_par.test +++ b/mysql-test/t/stat_tables_par.test @@ -242,4 +242,37 @@ DROP DATABASE dbt3_s001; use test; +# +# Bug mdev-4019: crash when executing in parallel ANALYZE and +# SELECT * FROM information_schema.statistics +# + +set @save_global_use_stat_tables=@@global.use_stat_tables; +set global use_stat_tables='preferably'; +set debug_sync='RESET'; + +create table t1 (a int, b int, key(a)); +insert t1 values (1,1),(2,2); + +analyze table t1; + +SET debug_sync='after_open_table_ignore_flush WAIT_FOR go'; +send select * from information_schema.statistics where table_schema='test'; + +connect(con1, localhost, root); +connection con1; +select * from t1; +SET DEBUG_SYNC= "now SIGNAL go"; + +connection default; +reap; + +connection default; +disconnect con1; +set debug_sync='RESET'; + +drop table t1; +set global use_stat_tables=@save_global_use_stat_tables; + + set use_stat_tables=@save_use_stat_tables; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b7f321e6290..cb1555ea142 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4654,6 +4654,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, Field **table_field_ptr= tables->table->field; for ( ; *field_ptr; field_ptr++, table_field_ptr++) (*table_field_ptr)->read_stats= (*field_ptr)->read_stats; + tables->table->stats_is_read= table_share->stats_cb.stats_is_read; } } } diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 9de5aa080e1..68f26ebf90b 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -2501,6 +2501,8 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) } } + table->stats_is_read= TRUE; + DBUG_RETURN(0); } @@ -2559,6 +2561,8 @@ bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables) table_share->stats_cb.stats_can_be_read && !table_share->stats_cb.stats_is_read) return TRUE; + if (table_share->stats_cb.stats_is_read) + tl->table->stats_is_read= TRUE; } } @@ -2618,6 +2622,8 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables) (void) read_statistics_for_table(thd, tl->table, stat_tables); table_share->stats_cb.stats_is_read= TRUE; } + if (table_share->stats_cb.stats_is_read) + tl->table->stats_is_read= TRUE; } } @@ -3045,7 +3051,7 @@ void set_statistics_for_table(THD *thd, TABLE *table) Use_stat_tables_mode use_stat_table_mode= get_use_stat_tables_mode(thd); table->used_stat_records= (use_stat_table_mode <= COMPLEMENTARY || - !stats_cb->stats_is_read || read_stats->cardinality_is_null) ? + !table->stats_is_read || read_stats->cardinality_is_null) ? table->file->stats.records : read_stats->cardinality; KEY *key_info, *key_info_end; for (key_info= table->key_info, key_info_end= key_info+table->s->keys; @@ -3053,7 +3059,7 @@ void set_statistics_for_table(THD *thd, TABLE *table) { key_info->is_statistics_from_stat_tables= (use_stat_table_mode > COMPLEMENTARY && - stats_cb->stats_is_read && + table->stats_is_read && key_info->read_stats->avg_frequency_is_inited() && key_info->read_stats->get_avg_frequency(0) > 0.5); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 78b693c5237..31df7a2a4b1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -32,6 +32,7 @@ #include "sql_view.h" // check_key_in_view #include "sp_head.h" #include "sql_trigger.h" +#include "sql_statistics.h" #include "probes_mysql.h" #include "debug_sync.h" #include "key.h" // is_key_used @@ -404,6 +405,7 @@ int mysql_update(THD *thd, #endif /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + set_statistics_for_table(thd, table); select= make_select(table, 0, 0, conds, 0, &error); if (error || !limit || thd->is_error() || diff --git a/sql/table.h b/sql/table.h index a2b197ac1f3..ac0eb0dad89 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1189,6 +1189,7 @@ public: bool no_partitions_used; /* If true, all partitions have been pruned away */ #endif uint max_keys; /* Size of allocated key_info array. */ + bool stats_is_read; /* Persistent statistics is read for the table */ MDL_ticket *mdl_ticket; void init(THD *thd, TABLE_LIST *tl); |