summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/sql_statistics.cc99
-rw-r--r--sql/table.cc2
-rw-r--r--sql/table.h75
3 files changed, 116 insertions, 60 deletions
diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc
index 0f8daa6e52f..a99dcca89e4 100644
--- a/sql/sql_statistics.cc
+++ b/sql/sql_statistics.cc
@@ -2204,27 +2204,13 @@ static int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share)
DBUG_ENTER("alloc_statistics_for_table_share");
- DEBUG_SYNC(thd, "statistics_mem_alloc_start1");
- DEBUG_SYNC(thd, "statistics_mem_alloc_start2");
-
- mysql_mutex_lock(&table_share->LOCK_share);
-
- if (stats_cb->stats_can_be_read)
- {
- mysql_mutex_unlock(&table_share->LOCK_share);
- DBUG_RETURN(0);
- }
-
Table_statistics *table_stats= stats_cb->table_stats;
if (!table_stats)
{
table_stats= (Table_statistics *) alloc_root(&stats_cb->mem_root,
sizeof(Table_statistics));
if (!table_stats)
- {
- mysql_mutex_unlock(&table_share->LOCK_share);
DBUG_RETURN(1);
- }
memset(table_stats, 0, sizeof(Table_statistics));
stats_cb->table_stats= table_stats;
}
@@ -2290,13 +2276,7 @@ static int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share)
}
}
}
-
- if (column_stats && index_stats && idx_avg_frequency)
- stats_cb->stats_can_be_read= TRUE;
-
- mysql_mutex_unlock(&table_share->LOCK_share);
-
- DBUG_RETURN(0);
+ DBUG_RETURN(column_stats && index_stats && idx_avg_frequency ? 0 : 1);
}
@@ -2913,11 +2893,22 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
Field **field_ptr;
KEY *key_info, *key_info_end;
TABLE_SHARE *table_share= table->s;
- Table_statistics *read_stats= table_share->stats_cb.table_stats;
DBUG_ENTER("read_statistics_for_table");
+ DEBUG_SYNC(thd, "statistics_mem_alloc_start1");
+ DEBUG_SYNC(thd, "statistics_mem_alloc_start2");
+
+ if (!table_share->stats_cb.start_stats_load())
+ DBUG_RETURN(table_share->stats_cb.stats_are_ready() ? 0 : 1);
+
+ if (alloc_statistics_for_table_share(thd, table_share))
+ {
+ table_share->stats_cb.abort_stats_load();
+ DBUG_RETURN(1);
+ }
/* Read statistics from the statistical table table_stats */
+ Table_statistics *read_stats= table_share->stats_cb.table_stats;
stat_table= stat_tables[TABLE_STAT].table;
Table_stat table_stat(stat_table, table);
table_stat.set_key_fields();
@@ -2995,9 +2986,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
}
}
}
-
- table->stats_is_read= TRUE;
-
+ table_share->stats_cb.end_stats_load();
DBUG_RETURN(0);
}
@@ -3146,6 +3135,23 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables)
}
+static void dump_stats_from_share_to_table(TABLE *table)
+{
+ TABLE_SHARE *table_share= table->s;
+ KEY *key_info= table_share->key_info;
+ KEY *key_info_end= key_info + table_share->keys;
+ KEY *table_key_info= table->key_info;
+ for ( ; key_info < key_info_end; key_info++, table_key_info++)
+ table_key_info->read_stats= key_info->read_stats;
+
+ Field **field_ptr= table_share->field;
+ Field **table_field_ptr= table->field;
+ for ( ; *field_ptr; field_ptr++, table_field_ptr++)
+ (*table_field_ptr)->read_stats= (*field_ptr)->read_stats;
+ table->stats_is_read= true;
+}
+
+
int read_statistics_for_tables(THD *thd, TABLE_LIST *tables)
{
TABLE_LIST stat_tables[STATISTICS_TABLES];
@@ -3167,30 +3173,17 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables)
{
if (table_share->table_category == TABLE_CATEGORY_USER)
{
- if (table_share->stats_cb.stats_can_be_read ||
- !alloc_statistics_for_table_share(thd, table_share))
+ if (table_share->stats_cb.stats_are_ready())
{
- if (table_share->stats_cb.stats_can_be_read)
- {
- KEY *key_info= table_share->key_info;
- KEY *key_info_end= key_info + table_share->keys;
- KEY *table_key_info= tl->table->key_info;
- for ( ; key_info < key_info_end; key_info++, table_key_info++)
- table_key_info->read_stats= key_info->read_stats;
- Field **field_ptr= table_share->field;
- Field **table_field_ptr= tl->table->field;
- for ( ; *field_ptr; field_ptr++, table_field_ptr++)
- (*table_field_ptr)->read_stats= (*field_ptr)->read_stats;
- tl->table->stats_is_read= table_share->stats_cb.stats_is_read;
- tl->table->histograms_are_read=
- table_share->stats_cb.histograms_are_read;
-
- if (!tl->table->stats_is_read ||
- (!table_share->stats_cb.histograms_are_read &&
- thd->variables.optimizer_use_condition_selectivity > 3))
- statistics_for_tables_is_needed= true;
- }
+ if (!tl->table->stats_is_read)
+ dump_stats_from_share_to_table(tl->table);
+ tl->table->histograms_are_read=
+ table_share->stats_cb.histograms_are_read;
+ if (table_share->stats_cb.histograms_are_read ||
+ thd->variables.optimizer_use_condition_selectivity <= 3)
+ continue;
}
+ statistics_for_tables_is_needed= true;
}
else if (is_stat_table(tl->db, tl->alias))
found_stat_table= true;
@@ -3217,16 +3210,14 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables)
table_share->tmp_table == NO_TMP_TABLE &&
table_share->table_category == TABLE_CATEGORY_USER)
{
- if (table_share->stats_cb.stats_can_be_read &&
- !table_share->stats_cb.stats_is_read)
+ if (!tl->table->stats_is_read)
{
- (void) read_statistics_for_table(thd, tl->table, stat_tables);
- table_share->stats_cb.stats_is_read= TRUE;
+ if (!read_statistics_for_table(thd, tl->table, stat_tables))
+ dump_stats_from_share_to_table(tl->table);
+ else
+ continue;
}
- if (table_share->stats_cb.stats_is_read)
- tl->table->stats_is_read= TRUE;
if (thd->variables.optimizer_use_condition_selectivity > 3 &&
- table_share->stats_cb.stats_can_be_read &&
!table_share->stats_cb.histograms_are_read)
{
(void) read_histograms_for_table(thd, tl->table, stat_tables);
diff --git a/sql/table.cc b/sql/table.cc
index 192faa0d00e..1d3bebcc5d5 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -416,8 +416,6 @@ void TABLE_SHARE::destroy()
delete_stat_values_for_table_share(this);
free_root(&stats_cb.mem_root, MYF(0));
- stats_cb.stats_can_be_read= FALSE;
- stats_cb.stats_is_read= FALSE;
stats_cb.histograms_can_be_read= FALSE;
stats_cb.histograms_are_read= FALSE;
diff --git a/sql/table.h b/sql/table.h
index 29b4cfdbcf3..85ba7b29ce2 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -594,15 +594,82 @@ enum open_frm_error {
from persistent statistical tables
*/
-struct TABLE_STATISTICS_CB
+class TABLE_STATISTICS_CB
{
+ class Statistics_state
+ {
+ enum state_codes
+ {
+ EMPTY, /** data is not loaded */
+ LOADING, /** data is being loaded in some connection */
+ READY /** data is loaded and available for use */
+ };
+ int32 state;
+
+ public:
+ /** No state copy */
+ Statistics_state &operator=(const Statistics_state &) { return *this; }
+
+ /** Checks if data loading have been completed */
+ bool is_ready() const
+ {
+ return my_atomic_load32_explicit(const_cast<int32*>(&state),
+ MY_MEMORY_ORDER_ACQUIRE) == READY;
+ }
+
+ /**
+ Sets mutual exclusion for data loading
+
+ If stats are in LOADING state, waits until state change.
+
+ @return
+ @retval true atomic EMPTY -> LOADING transfer completed, ok to load
+ @retval false stats are in READY state, no need to load
+ */
+ bool start_load()
+ {
+ for (;;)
+ {
+ int32 expected= EMPTY;
+ if (my_atomic_cas32_weak_explicit(&state, &expected, LOADING,
+ MY_MEMORY_ORDER_RELAXED,
+ MY_MEMORY_ORDER_RELAXED))
+ return true;
+ if (expected == READY)
+ return false;
+ (void) LF_BACKOFF;
+ }
+ }
+
+ /** Marks data available for subsequent use */
+ void end_load()
+ {
+ DBUG_ASSERT(my_atomic_load32_explicit(&state, MY_MEMORY_ORDER_RELAXED) ==
+ LOADING);
+ my_atomic_store32_explicit(&state, READY, MY_MEMORY_ORDER_RELEASE);
+ }
+
+ /** Restores empty state on error (e.g. OOM) */
+ void abort_load()
+ {
+ DBUG_ASSERT(my_atomic_load32_explicit(&state, MY_MEMORY_ORDER_RELAXED) ==
+ LOADING);
+ my_atomic_store32_explicit(&state, EMPTY, MY_MEMORY_ORDER_RELAXED);
+ }
+ };
+
+ class Statistics_state stats_state;
+
+public:
MEM_ROOT mem_root; /* MEM_ROOT to allocate statistical data for the table */
Table_statistics *table_stats; /* Structure to access the statistical data */
- bool stats_can_be_read; /* Memory for statistical data is allocated */
- bool stats_is_read; /* Statistical data for table has been read
- from statistical tables */
bool histograms_can_be_read;
bool histograms_are_read;
+
+ bool stats_are_ready() const { return stats_state.is_ready(); }
+ bool start_stats_load() { return stats_state.start_load(); }
+ void end_stats_load() { stats_state.end_load(); }
+ void abort_stats_load() { stats_state.abort_load(); }
};