Skip to content

Commit c3870e0

Browse files
author
V S Murthy Sidagam
committed
Bug #18592390 QUERY TO I_S.TABLES AND I_S.COLUMNS LEADS TO HUGE MEMORY USAGE
Description: On an example MySQL instance with 28k empty InnoDB tables, a specific query to information_schema.tables and information_schema.columns leads to memory consumption over 38GB RSS. Analysis: In get_all_tables() call, we fill the I_S tables from frm files and storage engine. As part of that process we call make_table_name_list() and allocate memory for all the 28k frm file names in the THD mem_root through make_lex_string_root(). Since it has been called around 28k * 28k times there is a huge memory getting hogged in THD mem_root. This causes the RSS to grow to 38GB. Fix: As part of fix we are creating a temporary mem_root in get_all_tables and passing it to fill_fiels(). There we replace the THD mem_root with the temporary mem_root and allocates the file names in temporary mem_root and frees it once we fill the I_S tables in get_all_tables and re-assign the original mem_root back to THD mem_root. Note: Checked the massif out put with the fix now the memory growth is just around 580MB at peak.
1 parent 7797ef4 commit c3870e0

File tree

2 files changed

+58
-14
lines changed

2 files changed

+58
-14
lines changed

sql/sql_show.cc

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -404,13 +404,14 @@ bool mysqld_show_privileges(THD *thd)
404404

405405
find_files_result
406406
find_files(THD *thd, List<LEX_STRING> *files, const char *db,
407-
const char *path, const char *wild, bool dir)
407+
const char *path, const char *wild, bool dir, MEM_ROOT *tmp_mem_root)
408408
{
409409
uint i;
410410
char *ext;
411411
MY_DIR *dirp;
412412
FILEINFO *file;
413413
LEX_STRING *file_name= 0;
414+
MEM_ROOT **root_ptr= NULL, *old_root= NULL;
414415
uint file_name_len;
415416
#ifndef NO_EMBEDDED_ACCESS_CHECKS
416417
uint col_access=thd->col_access;
@@ -440,6 +441,13 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
440441
DBUG_RETURN(FIND_FILES_DIR);
441442
}
442443

444+
if (tmp_mem_root)
445+
{
446+
root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
447+
old_root= *root_ptr;
448+
*root_ptr= tmp_mem_root;
449+
}
450+
443451
for (i=0 ; i < (uint) dirp->number_off_files ; i++)
444452
{
445453
char uname[NAME_LEN + 1]; /* Unencoded name */
@@ -519,8 +527,11 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
519527
continue;
520528
}
521529
#endif
522-
if (!(file_name=
523-
thd->make_lex_string(file_name, uname, file_name_len, TRUE)) ||
530+
if (!(file_name= tmp_mem_root ?
531+
make_lex_string_root(tmp_mem_root, file_name, uname,
532+
file_name_len, TRUE) :
533+
thd->make_lex_string(file_name, uname,
534+
file_name_len, TRUE)) ||
524535
files->push_back(file_name))
525536
{
526537
my_dirend(dirp);
@@ -532,6 +543,9 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
532543

533544
(void) ha_find_files(thd, db, path, wild, dir, files);
534545

546+
if (tmp_mem_root)
547+
*root_ptr= old_root;
548+
535549
DBUG_RETURN(FIND_FILES_OK);
536550
}
537551

@@ -2882,7 +2896,7 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
28822896

28832897
int make_db_list(THD *thd, List<LEX_STRING> *files,
28842898
LOOKUP_FIELD_VALUES *lookup_field_vals,
2885-
bool *with_i_schema)
2899+
bool *with_i_schema, MEM_ROOT *tmp_mem_root)
28862900
{
28872901
LEX_STRING *i_s_name_copy= 0;
28882902
i_s_name_copy= thd->make_lex_string(i_s_name_copy,
@@ -2906,7 +2920,8 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
29062920
return 1;
29072921
}
29082922
return (find_files(thd, files, NullS, mysql_data_home,
2909-
lookup_field_vals->db_value.str, 1) != FIND_FILES_OK);
2923+
lookup_field_vals->db_value.str, 1, tmp_mem_root) !=
2924+
FIND_FILES_OK);
29102925
}
29112926

29122927

@@ -2948,7 +2963,7 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
29482963
return 1;
29492964
*with_i_schema= 1;
29502965
return (find_files(thd, files, NullS,
2951-
mysql_data_home, NullS, 1) != FIND_FILES_OK);
2966+
mysql_data_home, NullS, 1, tmp_mem_root) != FIND_FILES_OK);
29522967
}
29532968

29542969

@@ -3056,7 +3071,8 @@ int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
30563071
static int
30573072
make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
30583073
LOOKUP_FIELD_VALUES *lookup_field_vals,
3059-
bool with_i_schema, LEX_STRING *db_name)
3074+
bool with_i_schema, LEX_STRING *db_name,
3075+
MEM_ROOT *tmp_mem_root)
30603076
{
30613077
char path[FN_REFLEN + 1];
30623078
build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
@@ -3110,7 +3126,8 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
31103126
lookup_field_vals->table_value.str));
31113127

31123128
find_files_result res= find_files(thd, table_names, db_name->str, path,
3113-
lookup_field_vals->table_value.str, 0);
3129+
lookup_field_vals->table_value.str, 0,
3130+
tmp_mem_root);
31143131
if (res != FIND_FILES_OK)
31153132
{
31163133
/*
@@ -3776,6 +3793,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
37763793
bool can_deadlock;
37773794
DBUG_ENTER("get_all_tables");
37783795

3796+
MEM_ROOT tmp_mem_root;
3797+
init_sql_alloc(&tmp_mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
3798+
37793799
/*
37803800
In cases when SELECT from I_S table being filled by this call is
37813801
part of statement which also uses other tables or is being executed
@@ -3867,7 +3887,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
38673887
goto err;
38683888
}
38693889

3870-
if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema))
3890+
if (make_db_list(thd, &db_names, &lookup_field_vals, &with_i_schema, &tmp_mem_root))
38713891
goto err;
38723892
it.rewind(); /* To get access to new elements in basis list */
38733893
while ((db_name= it++))
@@ -3885,7 +3905,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
38853905
List<LEX_STRING> table_names;
38863906
int res= make_table_name_list(thd, &table_names, lex,
38873907
&lookup_field_vals,
3888-
with_i_schema, db_name);
3908+
with_i_schema, db_name, &tmp_mem_root);
38893909
if (res == 2) /* Not fatal error, continue */
38903910
continue;
38913911
if (res)
@@ -3972,9 +3992,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
39723992
with_i_schema= 0;
39733993
}
39743994
}
3975-
39763995
error= 0;
39773996
err:
3997+
3998+
free_root(&tmp_mem_root, MYF(0));
39783999
thd->restore_backup_open_tables_state(&open_tables_state_backup);
39794000

39804001
DBUG_RETURN(error);
@@ -4000,6 +4021,27 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
40004021
Returning error status in this case leads to client hangup.
40014022
*/
40024023

4024+
/*
4025+
* A temporary class is created to free tmp_mem_root when we return from
4026+
* this function, since we have 'return' from this function from many
4027+
* places. This is just to avoid goto.
4028+
*/
4029+
class free_tmp_mem_root
4030+
{
4031+
public:
4032+
free_tmp_mem_root()
4033+
{
4034+
init_sql_alloc(&tmp_mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
4035+
}
4036+
~free_tmp_mem_root()
4037+
{
4038+
free_root(&tmp_mem_root, MYF(0));
4039+
}
4040+
MEM_ROOT tmp_mem_root;
4041+
};
4042+
4043+
free_tmp_mem_root dummy_member;
4044+
40034045
LOOKUP_FIELD_VALUES lookup_field_vals;
40044046
List<LEX_STRING> db_names;
40054047
LEX_STRING *db_name;
@@ -4013,11 +4055,12 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
40134055

40144056
if (get_lookup_field_values(thd, cond, tables, &lookup_field_vals))
40154057
DBUG_RETURN(0);
4058+
40164059
DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'",
40174060
lookup_field_vals.db_value.str,
40184061
lookup_field_vals.table_value.str));
40194062
if (make_db_list(thd, &db_names, &lookup_field_vals,
4020-
&with_i_schema))
4063+
&with_i_schema, &dummy_member.tmp_mem_root))
40214064
DBUG_RETURN(1);
40224065

40234066
/*

sql/sql_show.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -82,7 +82,8 @@ enum find_files_result {
8282
#define IS_FILES_EXTRA 37
8383

8484
find_files_result find_files(THD *thd, List<LEX_STRING> *files, const char *db,
85-
const char *path, const char *wild, bool dir);
85+
const char *path, const char *wild, bool dir,
86+
MEM_ROOT *tmp_mem_root);
8687

8788
int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
8889
HA_CREATE_INFO *create_info_arg, bool show_database);

0 commit comments

Comments
 (0)