1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

Fixed bug mdev-3891.

If a query referenced some system statistical tables, but not all of them,
then executing an ANALYZE command simultaneously with this query could
lead to a deadlock.
The fix prohibited reading statistics from system statistical tables
for such queries.

Removed the function unlock_tables_n_open_system_tables_for_write()
as not used anymore.
Performed some minor refactoring of the code in sql_statistics.cc.
This commit is contained in:
Igor Babaev
2012-12-12 23:16:54 -08:00
parent 109c104d07
commit 65820439bd
6 changed files with 140 additions and 107 deletions

View File

@ -126,6 +126,38 @@ inline void init_table_list_for_single_stat_table(TABLE_LIST *tbl,
}
/**
@brief
Open all statistical tables and lock them
*/
static
inline int open_stat_tables(THD *thd, TABLE_LIST *tables,
Open_tables_backup *backup,
bool for_write)
{
init_table_list_for_stat_tables(tables, for_write);
init_mdl_requests(tables);
return open_system_tables_for_read(thd, tables, backup);
}
/**
@brief
Open a statistical table and lock it
*/
static
inline int open_single_stat_table(THD *thd, TABLE_LIST *table,
const LEX_STRING *stat_tab_name,
Open_tables_backup *backup,
bool for_write)
{
init_table_list_for_single_stat_table(table, stat_tab_name, for_write);
init_mdl_requests(table);
return open_system_tables_for_read(thd, table, backup);
}
/**
@details
If the value of the parameter is_safe is TRUE then the function
@ -1199,7 +1231,7 @@ public:
the number of distinct values for a column. The class employs the
Unique class for this purpose.
The class Count_distinct_field is used only by the function
collect_statistics_from_table to calculate the values for
collect_statistics_for_table to calculate the values for
column avg_frequency of the statistical table column_stats.
*/
@ -2179,12 +2211,9 @@ int update_statistics_for_table(THD *thd, TABLE *table)
DBUG_ENTER("update_statistics_for_table");
init_table_list_for_stat_tables(tables, TRUE);
init_mdl_requests(tables);
DEBUG_SYNC(thd, "statistics_update_start");
if (unlock_tables_n_open_system_tables_for_write(thd,
tables,
&open_tables_backup))
if (open_stat_tables(thd, tables, &open_tables_backup, TRUE))
{
thd->clear_error();
DBUG_RETURN(rc);
@ -2266,7 +2295,7 @@ int update_statistics_for_table(THD *thd, TABLE *table)
The parameter stat_tables should point to an array of TABLE_LIST
objects for all statistical tables linked into a list. All statistical
tables are supposed to be opened.
The function is called by read_statistics_for_table_if_needed().
The function is called by read_statistics_for_tables_if_needed().
@retval
0 If data has been successfully read for the table
@ -2415,6 +2444,21 @@ bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables)
return FALSE;
}
/*
Do not read statistics for any query over non-user tables.
If the query references some statistical tables, but not all
of them, reading the statistics may lead to a deadlock
*/
for (TABLE_LIST *tl= tables; tl; tl= tl->next_global)
{
if (!tl->is_view_or_derived() && tl->table)
{
TABLE_SHARE *table_share= tl->table->s;
if (table_share && table_share->table_category != TABLE_CATEGORY_USER)
return FALSE;
}
}
for (TABLE_LIST *tl= tables; tl; tl= tl->next_global)
{
if (!tl->is_view_or_derived() && tl->table)
@ -2460,12 +2504,12 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables)
DBUG_ENTER("read_statistics_for_table_if_needed");
DEBUG_SYNC(thd, "statistics_read_start");
if (!statistics_for_tables_is_needed(thd, tables))
DBUG_RETURN(0);
init_table_list_for_stat_tables(stat_tables, FALSE);
init_mdl_requests(stat_tables);
if (open_system_tables_for_read(thd, stat_tables, &open_tables_backup))
if (open_stat_tables(thd, stat_tables, &open_tables_backup, FALSE))
{
thd->clear_error();
DBUG_RETURN(1);
@ -2527,12 +2571,7 @@ int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab)
DBUG_ENTER("delete_statistics_for_table");
init_table_list_for_stat_tables(tables, TRUE);
init_mdl_requests(tables);
if (open_system_tables_for_read(thd,
tables,
&open_tables_backup))
if (open_stat_tables(thd, tables, &open_tables_backup, TRUE))
{
thd->clear_error();
DBUG_RETURN(rc);
@ -2619,12 +2658,8 @@ int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col)
DBUG_ENTER("delete_statistics_for_column");
init_table_list_for_single_stat_table(&tables, &stat_table_name[1], TRUE);
init_mdl_requests(&tables);
if (open_system_tables_for_read(thd,
&tables,
&open_tables_backup))
if (open_single_stat_table(thd, &tables, &stat_table_name[1],
&open_tables_backup, TRUE))
{
thd->clear_error();
DBUG_RETURN(rc);
@ -2692,12 +2727,8 @@ int delete_statistics_for_index(THD *thd, TABLE *tab, KEY *key_info,
DBUG_ENTER("delete_statistics_for_index");
init_table_list_for_single_stat_table(&tables, &stat_table_name[2], TRUE);
init_mdl_requests(&tables);
if (open_system_tables_for_read(thd,
&tables,
&open_tables_backup))
if (open_single_stat_table(thd, &tables, &stat_table_name[2],
&open_tables_backup, TRUE))
{
thd->clear_error();
DBUG_RETURN(rc);
@ -2779,12 +2810,7 @@ int rename_table_in_stat_tables(THD *thd, LEX_STRING *db, LEX_STRING *tab,
DBUG_ENTER("rename_table_in_stat_tables");
init_table_list_for_stat_tables(tables, TRUE);
init_mdl_requests(tables);
if (open_system_tables_for_read(thd,
tables,
&open_tables_backup))
if (open_stat_tables(thd, tables, &open_tables_backup, TRUE))
{
thd->clear_error();
DBUG_RETURN(rc);
@ -2876,12 +2902,8 @@ int rename_column_in_stat_tables(THD *thd, TABLE *tab, Field *col,
DBUG_ENTER("rename_column_in_stat_tables");
init_table_list_for_single_stat_table(&tables, &stat_table_name[1], TRUE);
init_mdl_requests(&tables);
if (open_system_tables_for_read(thd,
&tables,
&open_tables_backup))
if (open_single_stat_table(thd, &tables, &stat_table_name[1],
&open_tables_backup, TRUE))
{
thd->clear_error();
DBUG_RETURN(rc);