Commit 97883d3c authored by Dmitry Shulga's avatar Dmitry Shulga

Fixed bug#11753187 (formerly known as bug 44585): SP_CACHE BEHAVES AS

MEMORY LEAK.

Background:
 - There are caches for stored functions and stored procedures (SP-cache);
 - There is no similar cache for events;
 - Triggers are cached together with TABLE objects;
 - Those SP-caches are per-session (i.e. specific to each session);
 - A stored routine is represented by a sp_head-instance internally;
 - SP-cache basically contains sp_head-objects of stored routines, which
   have been executed in a session;
 - sp_head-object is added into the SP-cache before the corresponding
   stored routine is executed;
 - SP-cache is flushed in the end of the session.

The problem was that SP-cache might grow without any limit. Although this
was not a pure memory leak (the SP-cache is flushed when session is closed),
this is still a problem, because the user might take much memory by
executing many stored routines.

The patch fixes this problem in the least-intrusive way. A soft limit
(similar to the size of table definition cache) is introduced. To represent
such limit the new runtime configuration parameter 'stored_program_cache'
is introduced. The value of this parameter is stored in the new global
variable stored_program_cache_size that used to control the size of SP-cache
to overflow. 

The parameter 'stored_program_cache' limits number of cached routines for
each thread. It has the following min/default/max values given from support:
  min = 256, default = 256, max = 512 * 1024.
Also it should be noted that this parameter limits the size of 
each cache (for stored procedures and for stored functions) separately.

The SP-cache size is checked after top-level statement is parsed.
If SP-cache size exceeds the limit specified by parameter
'stored_program_cache' then SP-cache is flushed and memory allocated for
cache objects is freed. Such approach allows to flush cache safely 
when there are dependencies among stored routines.


sql/mysqld.cc:
  Added global variable stored_program_cache_size to store value of
  configuration parameter 'stored-program-cache'.
sql/mysqld.h:
  Added declaration of global variable stored_program_cache_size.
sql/sp_cache.cc:
  Extended interface for sp_cache by adding helper routine
  sp_cache_enforce_limit to control size of stored routines cache for
  overflow. Also added method enforce_limit into class sp_cache that
  implements control of cache size for overflow.
sql/sp_cache.h:
  Extended interface for sp_cache by adding standalone routine
  sp_cache_enforce_limit to control size of stored routines cache
  for overflow.
sql/sql_parse.cc:
  Added flush of sp_cache after processing of next sql-statement
  received from a client.
sql/sql_prepare.cc:
  Added flush of sp_cache after preparation/execution of next prepared
  sql-statement received from a client.
sql/sys_vars.cc:
  Added support for configuration parameter stored-program-cache.
parent 82fec153
...@@ -671,6 +671,9 @@ The following options may be given as the first argument: ...@@ -671,6 +671,9 @@ The following options may be given as the first argument:
replication. replication.
--sql-mode=name Syntax: sql-mode=mode[,mode[,mode...]]. See the manual --sql-mode=name Syntax: sql-mode=mode[,mode[,mode...]]. See the manual
for the complete list of valid sql modes for the complete list of valid sql modes
--stored-program-cache=#
The soft upper limit for number of cached stored routines
for one connection.
-s, --symbolic-links -s, --symbolic-links
Enable symbolic link support. Enable symbolic link support.
--sync-binlog=# Synchronously flush binary log to disk after every #th --sync-binlog=# Synchronously flush binary log to disk after every #th
...@@ -935,6 +938,7 @@ slow-query-log FALSE ...@@ -935,6 +938,7 @@ slow-query-log FALSE
sort-buffer-size 2097152 sort-buffer-size 2097152
sporadic-binlog-dump-fail FALSE sporadic-binlog-dump-fail FALSE
sql-mode sql-mode
stored-program-cache 256
symbolic-links FALSE symbolic-links FALSE
sync-binlog 0 sync-binlog 0
sync-frm TRUE sync-frm TRUE
......
...@@ -679,6 +679,9 @@ The following options may be given as the first argument: ...@@ -679,6 +679,9 @@ The following options may be given as the first argument:
--sql-mode=name Syntax: sql-mode=mode[,mode[,mode...]]. See the manual --sql-mode=name Syntax: sql-mode=mode[,mode[,mode...]]. See the manual
for the complete list of valid sql modes for the complete list of valid sql modes
--standalone Dummy option to start as a standalone program (NT). --standalone Dummy option to start as a standalone program (NT).
--stored-program-cache=#
The soft upper limit for number of cached stored routines
for one connection.
-s, --symbolic-links -s, --symbolic-links
Enable symbolic link support. Enable symbolic link support.
--sync-binlog=# Synchronously flush binary log to disk after every #th --sync-binlog=# Synchronously flush binary log to disk after every #th
...@@ -946,6 +949,7 @@ slow-start-timeout 15000 ...@@ -946,6 +949,7 @@ slow-start-timeout 15000
sort-buffer-size 2097152 sort-buffer-size 2097152
sporadic-binlog-dump-fail FALSE sporadic-binlog-dump-fail FALSE
sql-mode sql-mode
stored-program-cache 256
symbolic-links FALSE symbolic-links FALSE
sync-binlog 0 sync-binlog 0
sync-frm TRUE sync-frm TRUE
......
# Saving initial value of stored_program_cache in a temporary variable
SET @start_value = @@global.stored_program_cache;
SELECT @start_value;
@start_value
256
# Display the DEFAULT value of stored_program_cache
SET @@global.stored_program_cache = DEFAULT;
SELECT @@global.stored_program_cache;
@@global.stored_program_cache
256
# Verify default value of variable
SELECT @@global.stored_program_cache = 256;
@@global.stored_program_cache = 256
1
# Change the value of stored_program_cache to a valid value
SET @@global.stored_program_cache = 512;
SELECT @@global.stored_program_cache;
@@global.stored_program_cache
512
# Change the value of stored_program_cache to invalid value
SET @@global.stored_program_cache = -1;
Warnings:
Warning 1292 Truncated incorrect stored_program_cache value: '-1'
SELECT @@global.stored_program_cache;
@@global.stored_program_cache
256
SET @@global.stored_program_cache =100000000000;
Warnings:
Warning 1292 Truncated incorrect stored_program_cache value: '100000000000'
SELECT @@global.stored_program_cache;
@@global.stored_program_cache
524288
SET @@global.stored_program_cache = 0;
Warnings:
Warning 1292 Truncated incorrect stored_program_cache value: '0'
SELECT @@global.stored_program_cache;
@@global.stored_program_cache
256
SET @@global.stored_program_cache = 10000.01;
ERROR 42000: Incorrect argument type to variable 'stored_program_cache'
SET @@global.stored_program_cache = ON;
ERROR 42000: Incorrect argument type to variable 'stored_program_cache'
SET @@global.stored_program_cache= 'test';
ERROR 42000: Incorrect argument type to variable 'stored_program_cache'
SET @@global.stored_program_cache = '';
ERROR 42000: Incorrect argument type to variable 'stored_program_cache'
# Test if accessing session stored_program_cache gives error
SET @@session.stored_program_cache = 0;
ERROR HY000: Variable 'stored_program_cache' is a GLOBAL variable and should be set with SET GLOBAL
# Check if accessing variable without SCOPE points to same global variable
SET @@global.stored_program_cache = 512;
SELECT @@stored_program_cache = @@global.stored_program_cache;
@@stored_program_cache = @@global.stored_program_cache
1
# Restore initial value
SET @@global.stored_program_cache = @start_value;
SELECT @@global.stored_program_cache;
@@global.stored_program_cache
256
# Variable Name: stored_program_cache
# Scope: GLOBAL
# Access Type: Dynamic
# Data Type: numeric
# Default Value: 256
# Range: 256-524288
--source include/load_sysvars.inc
--echo # Saving initial value of stored_program_cache in a temporary variable
SET @start_value = @@global.stored_program_cache;
SELECT @start_value;
--echo # Display the DEFAULT value of stored_program_cache
SET @@global.stored_program_cache = DEFAULT;
SELECT @@global.stored_program_cache;
--echo # Verify default value of variable
SELECT @@global.stored_program_cache = 256;
--echo # Change the value of stored_program_cache to a valid value
SET @@global.stored_program_cache = 512;
SELECT @@global.stored_program_cache;
--echo # Change the value of stored_program_cache to invalid value
SET @@global.stored_program_cache = -1;
SELECT @@global.stored_program_cache;
SET @@global.stored_program_cache =100000000000;
SELECT @@global.stored_program_cache;
SET @@global.stored_program_cache = 0;
SELECT @@global.stored_program_cache;
--Error ER_WRONG_TYPE_FOR_VAR
SET @@global.stored_program_cache = 10000.01;
--Error ER_WRONG_TYPE_FOR_VAR
SET @@global.stored_program_cache = ON;
--Error ER_WRONG_TYPE_FOR_VAR
SET @@global.stored_program_cache= 'test';
--Error ER_WRONG_TYPE_FOR_VAR
SET @@global.stored_program_cache = '';
--echo # Test if accessing session stored_program_cache gives error
--Error ER_GLOBAL_VARIABLE
SET @@session.stored_program_cache = 0;
--echo # Check if accessing variable without SCOPE points to same global variable
SET @@global.stored_program_cache = 512;
SELECT @@stored_program_cache = @@global.stored_program_cache;
--echo # Restore initial value
SET @@global.stored_program_cache = @start_value;
SELECT @@global.stored_program_cache;
...@@ -511,6 +511,11 @@ uint sync_binlog_period= 0, sync_relaylog_period= 0, ...@@ -511,6 +511,11 @@ uint sync_binlog_period= 0, sync_relaylog_period= 0,
sync_relayloginfo_period= 0, sync_masterinfo_period= 0; sync_relayloginfo_period= 0, sync_masterinfo_period= 0;
ulong expire_logs_days = 0; ulong expire_logs_days = 0;
ulong rpl_recovery_rank=0; ulong rpl_recovery_rank=0;
/**
Soft upper limit for number of sp_head objects that can be stored
in the sp_cache for one connection.
*/
ulong stored_program_cache_size= 0;
const double log_10[] = { const double log_10[] = {
1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009, 1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009,
......
...@@ -181,6 +181,7 @@ extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size; ...@@ -181,6 +181,7 @@ extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size;
extern ulong max_binlog_size, max_relay_log_size; extern ulong max_binlog_size, max_relay_log_size;
extern ulong opt_binlog_rows_event_max_size; extern ulong opt_binlog_rows_event_max_size;
extern ulong rpl_recovery_rank, thread_cache_size; extern ulong rpl_recovery_rank, thread_cache_size;
extern ulong stored_program_cache_size;
extern ulong back_log; extern ulong back_log;
extern char language[FN_REFLEN]; extern char language[FN_REFLEN];
extern "C" MYSQL_PLUGIN_IMPORT ulong server_id; extern "C" MYSQL_PLUGIN_IMPORT ulong server_id;
......
...@@ -57,6 +57,20 @@ class sp_cache ...@@ -57,6 +57,20 @@ class sp_cache
{ {
my_hash_delete(&m_hashtable, (uchar *)sp); my_hash_delete(&m_hashtable, (uchar *)sp);
} }
/**
Remove all elements from a stored routine cache if the current
number of elements exceeds the argument value.
@param[in] upper_limit_for_elements Soft upper limit of elements that
can be stored in the cache.
*/
void enforce_limit(ulong upper_limit_for_elements)
{
if (m_hashtable.records > upper_limit_for_elements)
my_hash_reset(&m_hashtable);
}
private: private:
void init(); void init();
void cleanup(); void cleanup();
...@@ -228,6 +242,21 @@ ulong sp_cache_version() ...@@ -228,6 +242,21 @@ ulong sp_cache_version()
} }
/**
Enforce that the current number of elements in the cache don't exceed
the argument value by flushing the cache if necessary.
@param[in] c Cache to check
@param[in] upper_limit_for_elements Soft upper limit for number of sp_head
objects that can be stored in the cache.
*/
void
sp_cache_enforce_limit(sp_cache *c, ulong upper_limit_for_elements)
{
if (c)
c->enforce_limit(upper_limit_for_elements);
}
/************************************************************************* /*************************************************************************
Internal functions Internal functions
*************************************************************************/ *************************************************************************/
......
...@@ -62,5 +62,6 @@ sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); ...@@ -62,5 +62,6 @@ sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
void sp_cache_invalidate(); void sp_cache_invalidate();
void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp); void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp);
ulong sp_cache_version(); ulong sp_cache_version();
void sp_cache_enforce_limit(sp_cache *cp, ulong upper_limit_for_elements);
#endif /* _SP_CACHE_H_ */ #endif /* _SP_CACHE_H_ */
...@@ -5632,6 +5632,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, ...@@ -5632,6 +5632,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
query_cache_abort(&thd->query_cache_tls); query_cache_abort(&thd->query_cache_tls);
} }
thd_proc_info(thd, "freeing items"); thd_proc_info(thd, "freeing items");
sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);
thd->end_statement(); thd->end_statement();
thd->cleanup_after_query(); thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty()); DBUG_ASSERT(thd->change_list.is_empty());
......
...@@ -2195,6 +2195,9 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) ...@@ -2195,6 +2195,9 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
thd->protocol= save_protocol; thd->protocol= save_protocol;
sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);
/* check_prepared_statemnt sends the metadata packet in case of success */ /* check_prepared_statemnt sends the metadata packet in case of success */
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2560,6 +2563,9 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) ...@@ -2560,6 +2563,9 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end); stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
thd->protocol= save_protocol; thd->protocol= save_protocol;
sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);
/* Close connection socket; for use with client testing (Bug#43560). */ /* Close connection socket; for use with client testing (Bug#43560). */
DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio);); DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););
......
...@@ -3253,6 +3253,13 @@ static Sys_var_tz Sys_time_zone( ...@@ -3253,6 +3253,13 @@ static Sys_var_tz Sys_time_zone(
SESSION_VAR(time_zone), NO_CMD_LINE, SESSION_VAR(time_zone), NO_CMD_LINE,
DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG); DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG);
static Sys_var_ulong Sys_sp_cache_size(
"stored_program_cache",
"The soft upper limit for number of cached stored routines for "
"one connection.",
GLOBAL_VAR(stored_program_cache_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(256, 512 * 1024), DEFAULT(256), BLOCK_SIZE(1));
/**************************************************************************** /****************************************************************************
Used templates Used templates
......
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