1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

Fix histogram memory management

There are "local" histograms that are allocated by one thread for
one TABLE object, and "global" that are allocated for TABLE_SHARE.
This commit is contained in:
Sergei Petrunia
2021-08-29 23:55:39 +03:00
parent 032587e2dc
commit a93b377863
3 changed files with 50 additions and 11 deletions

View File

@ -1045,6 +1045,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
else else
compl_result_code= HA_ADMIN_FAILED; compl_result_code= HA_ADMIN_FAILED;
free_statistics_for_table(thd, table->table);
if (compl_result_code) if (compl_result_code)
result_code= HA_ADMIN_FAILED; result_code= HA_ADMIN_FAILED;
else else

View File

@ -63,7 +63,8 @@
equal to "never". equal to "never".
*/ */
Histogram_base *create_histogram(MEM_ROOT *mem_root, Histogram_type hist_type); Histogram_base *create_histogram(MEM_ROOT *mem_root, Histogram_type hist_type,
THD *owner);
/* Currently there are only 3 persistent statistical tables */ /* Currently there are only 3 persistent statistical tables */
static const uint STATISTICS_TABLES= 3; static const uint STATISTICS_TABLES= 3;
@ -1222,15 +1223,16 @@ public:
char buff[MAX_FIELD_WIDTH]; char buff[MAX_FIELD_WIDTH];
String val(buff, sizeof(buff), &my_charset_bin); String val(buff, sizeof(buff), &my_charset_bin);
uint fldno= COLUMN_STAT_HISTOGRAM; uint fldno= COLUMN_STAT_HISTOGRAM;
Histogram_base *hist;
Field *stat_field= stat_table->field[fldno]; Field *stat_field= stat_table->field[fldno];
table_field->read_stats->set_not_null(fldno); table_field->read_stats->set_not_null(fldno);
stat_field->val_str(&val); stat_field->val_str(&val);
hist= create_histogram(mem_root, table_field->read_stats->histogram_type_on_disk); Histogram_type hist_type=
if (!hist) table_field->read_stats->histogram_type_on_disk;
Histogram_base *hist;
if (!(hist= create_histogram(mem_root, hist_type, NULL)))
return NULL; return NULL;
if (!hist->parse(mem_root, table_field, if (!hist->parse(mem_root, table_field, hist_type,
table_field->read_stats->histogram_type_on_disk,
val.ptr(), val.length())) val.ptr(), val.length()))
{ {
table_field->read_stats->histogram_= hist; table_field->read_stats->histogram_= hist;
@ -2085,18 +2087,25 @@ public:
}; };
Histogram_base *create_histogram(MEM_ROOT *mem_root, Histogram_type hist_type) Histogram_base *create_histogram(MEM_ROOT *mem_root, Histogram_type hist_type,
THD *owner)
{ {
Histogram_base *res= NULL;
switch (hist_type) { switch (hist_type) {
case SINGLE_PREC_HB: case SINGLE_PREC_HB:
case DOUBLE_PREC_HB: case DOUBLE_PREC_HB:
return new (mem_root) Histogram_binary(); res= new (mem_root) Histogram_binary();
break;
case JSON_HB: case JSON_HB:
return new (mem_root) Histogram_json(); res= new (mem_root) Histogram_json();
break;
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
return NULL;
if (res)
res->set_owner(owner);
return res;
} }
@ -2691,6 +2700,25 @@ int alloc_statistics_for_table(THD* thd, TABLE *table)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/*
Free the "local" statistics for table.
We only free the statistics that is not on MEM_ROOT and needs to be
explicitly freed.
*/
void free_statistics_for_table(THD *thd, TABLE *table)
{
for (Field **field_ptr= table->field; *field_ptr; field_ptr++)
{
// Only delete the histograms that are exclusivly owned by this thread
if ((*field_ptr)->collected_stats &&
(*field_ptr)->collected_stats->histogram_ &&
(*field_ptr)->collected_stats->histogram_->get_owner() == thd)
{
delete (*field_ptr)->collected_stats->histogram_;
(*field_ptr)->collected_stats->histogram_= NULL;
}
}
}
/** /**
@brief @brief
@ -2921,7 +2949,7 @@ void Column_statistics_collected::finish(MEM_ROOT *mem_root, ha_rows rows, doubl
if (hist_size != 0 && hist_type != INVALID_HISTOGRAM) if (hist_size != 0 && hist_type != INVALID_HISTOGRAM)
{ {
have_histogram= true; have_histogram= true;
histogram_= create_histogram(mem_root, hist_type); histogram_= create_histogram(mem_root, hist_type, current_thd);
histogram_->init_for_collection(mem_root, hist_type, hist_size); histogram_->init_for_collection(mem_root, hist_type, hist_size);
} }

View File

@ -125,6 +125,7 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables);
int collect_statistics_for_table(THD *thd, TABLE *table); int collect_statistics_for_table(THD *thd, TABLE *table);
void delete_stat_values_for_table_share(TABLE_SHARE *table_share); void delete_stat_values_for_table_share(TABLE_SHARE *table_share);
int alloc_statistics_for_table(THD *thd, TABLE *table); int alloc_statistics_for_table(THD *thd, TABLE *table);
void free_statistics_for_table(THD *thd, TABLE *table);
int update_statistics_for_table(THD *thd, TABLE *table); int update_statistics_for_table(THD *thd, TABLE *table);
int delete_statistics_for_table(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab); int delete_statistics_for_table(THD *thd, const LEX_CSTRING *db, const LEX_CSTRING *tab);
int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col); int delete_statistics_for_column(THD *thd, TABLE *tab, Field *col);
@ -176,6 +177,15 @@ public:
// Newer, JSON-based histograms may return 0. // Newer, JSON-based histograms may return 0.
virtual uint get_size()=0; virtual uint get_size()=0;
virtual ~Histogram_base()= default; virtual ~Histogram_base()= default;
Histogram_base() : owner(NULL) {}
THD *get_owner() { return owner; }
void set_owner(THD *thd) { owner=thd; }
private:
// Owner is a thread that *exclusively* owns this histogram (and so can
// delete it at any time)
THD *owner;
}; };