Commit 7d5c56cb authored by Igor Babaev's avatar Igor Babaev

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.
parent 7d9df807
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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;
}
}
}
......
......@@ -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);
}
......
......@@ -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() ||
......
......@@ -1189,6 +1189,7 @@ struct TABLE
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment