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.
This commit is contained in:
parent
7bec00e131
commit
d460f1689d
@ -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
|
|||||||
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:
|
|||||||
--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
|
|||||||
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
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
# 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
|
59
mysql-test/suite/sys_vars/t/stored_program_cache_basic.test
Normal file
59
mysql-test/suite/sys_vars/t/stored_program_cache_basic.test
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# 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,
|
|||||||
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;
|
|||||||
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 @@ public:
|
|||||||
{
|
{
|
||||||
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()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
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);
|
|||||||
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,
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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(
|
|||||||
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user