Commit 8070c06a authored by unknown's avatar unknown

SP cache (WL#730). (Mostly by vva, additions by pem.)


sql/sp.cc:
  In-memory cache added.
  sp_clear_function_cache() no longer needed.
sql/sp.h:
  In-memory cache added.
  sp_clear_function_cache() no longer needed.
sql/sql_class.cc:
  In-memory cache added.
sql/sql_class.h:
  In-memory cache added.
sql/sql_parse.cc:
  In-memory cache added.
  sp_clear_function_cache() no longer needed.
  Don't delete sp_heads after each use.
parent 31a58c40
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
static sp_head * static sp_head *
sp_find_cached_function(THD *thd, char *name, uint namelen); sp_find_cached_function(THD *thd, char *name, uint namelen);
static sp_head *
sp_find_cached_procedure(THD *thd, char *name, uint namelen);
/* /*
* *
* DB storage of Stored PROCEDUREs and FUNCTIONs * DB storage of Stored PROCEDUREs and FUNCTIONs
...@@ -254,9 +257,17 @@ sp_find_procedure(THD *thd, LEX_STRING *name) ...@@ -254,9 +257,17 @@ sp_find_procedure(THD *thd, LEX_STRING *name)
DBUG_PRINT("enter", ("name: %*s", name->length, name->str)); DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
if (db_find_routine(thd, TYPE_ENUM_PROCEDURE, sp= sp_find_cached_procedure(thd, name->str, name->length);
name->str, name->length, &sp) != SP_OK) if (! sp)
sp= NULL; {
if (db_find_routine(thd, TYPE_ENUM_PROCEDURE,
name->str, name->length, &sp) == SP_OK)
{
HASH *phash= thd->sp_hash+TYPE_ENUM_PROCEDURE-1;
hash_insert(phash, (const byte*)sp);
}
}
DBUG_RETURN(sp); DBUG_RETURN(sp);
} }
...@@ -280,8 +291,17 @@ sp_drop_procedure(THD *thd, char *name, uint namelen) ...@@ -280,8 +291,17 @@ sp_drop_procedure(THD *thd, char *name, uint namelen)
{ {
DBUG_ENTER("sp_drop_procedure"); DBUG_ENTER("sp_drop_procedure");
DBUG_PRINT("enter", ("name: %*s", namelen, name)); DBUG_PRINT("enter", ("name: %*s", namelen, name));
sp_head *sp;
int ret; int ret;
sp= sp_find_cached_procedure(thd, name, namelen);
if (sp)
{
HASH *phash= thd->sp_hash+TYPE_ENUM_PROCEDURE-1;
hash_delete(phash, (byte*)sp);
delete sp;
}
ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen); ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen);
DBUG_RETURN(ret); DBUG_RETURN(ret);
...@@ -331,8 +351,17 @@ sp_drop_function(THD *thd, char *name, uint namelen) ...@@ -331,8 +351,17 @@ sp_drop_function(THD *thd, char *name, uint namelen)
{ {
DBUG_ENTER("sp_drop_function"); DBUG_ENTER("sp_drop_function");
DBUG_PRINT("enter", ("name: %*s", namelen, name)); DBUG_PRINT("enter", ("name: %*s", namelen, name));
sp_head *sp;
int ret; int ret;
sp= sp_find_cached_function(thd, name, namelen);
if (sp)
{
HASH *fhash= thd->sp_hash+TYPE_ENUM_FUNCTION-1;
hash_delete(fhash, (byte*)sp);
delete sp;
}
ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen); ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen);
DBUG_RETURN(ret); DBUG_RETURN(ret);
...@@ -344,9 +373,10 @@ sp_function_exists(THD *thd, LEX_STRING *name) ...@@ -344,9 +373,10 @@ sp_function_exists(THD *thd, LEX_STRING *name)
{ {
TABLE *table; TABLE *table;
bool ret= FALSE; bool ret= FALSE;
bool opened; bool opened= FALSE;
if (db_find_routine_aux(thd, TYPE_ENUM_FUNCTION, if (sp_find_cached_function(thd, name->str, name->length) ||
db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
name->str, name->length, TL_READ, name->str, name->length, TL_READ,
&table, &opened) == SP_OK) &table, &opened) == SP_OK)
{ {
...@@ -358,13 +388,6 @@ sp_function_exists(THD *thd, LEX_STRING *name) ...@@ -358,13 +388,6 @@ sp_function_exists(THD *thd, LEX_STRING *name)
} }
/*
*
* The temporary FUNCTION cache. (QQ This will be rehacked later, but
* it's needed now to make functions work at all.)
*
*/
void void
sp_add_fun_to_lex(LEX *lex, LEX_STRING fun) sp_add_fun_to_lex(LEX *lex, LEX_STRING fun)
{ {
...@@ -411,25 +434,22 @@ sp_cache_functions(THD *thd, LEX *lex) ...@@ -411,25 +434,22 @@ sp_cache_functions(THD *thd, LEX *lex)
char *fn; char *fn;
enum_sql_command cmd= lex->sql_command; enum_sql_command cmd= lex->sql_command;
int ret= 0; int ret= 0;
HASH *fhash= thd->sp_hash+TYPE_ENUM_FUNCTION-1;
while ((fn= li++)) while ((fn= li++))
{ {
List_iterator_fast<sp_head> lisp(thd->spfuns);
sp_head *sp; sp_head *sp;
int len= strlen(fn);
while ((sp= lisp++)) if (hash_search(fhash,(const byte*)fn,len))
{
if (my_strcasecmp(system_charset_info, fn, sp->name()) == 0)
break;
}
if (sp)
continue; continue;
if (db_find_routine(thd, TYPE_ENUM_FUNCTION, fn, strlen(fn), &sp) == SP_OK)
if (db_find_routine(thd, TYPE_ENUM_FUNCTION, fn, len, &sp) == SP_OK)
{ {
ret= sp_cache_functions(thd, thd->lex); ret= sp_cache_functions(thd, thd->lex);
if (ret) if (ret)
break; break;
thd->spfuns.push_back(sp); hash_insert(fhash,(const byte*)sp);
} }
else else
{ {
...@@ -441,32 +461,23 @@ sp_cache_functions(THD *thd, LEX *lex) ...@@ -441,32 +461,23 @@ sp_cache_functions(THD *thd, LEX *lex)
return ret; return ret;
} }
void byte *
sp_clear_function_cache(THD *thd) hash_get_key_for_sp_head(const byte *ptr, uint *plen,
my_bool first)
{ {
List_iterator_fast<sp_head> li(thd->spfuns); return ((sp_head*)ptr)->name(plen);
sp_head *sp;
while ((sp= li++))
delete sp;
thd->spfuns.empty();
} }
static sp_head * static sp_head *
sp_find_cached_function(THD *thd, char *name, uint namelen) sp_find_cached_function(THD *thd, char *name, uint namelen)
{ {
List_iterator_fast<sp_head> li(thd->spfuns); return (sp_head*)hash_search(thd->sp_hash+TYPE_ENUM_FUNCTION-1,
sp_head *sp; (const byte*)name,namelen);
}
while ((sp= li++))
{
uint len;
const uchar *n= (const uchar *)sp->name(&len);
if (my_strnncoll(system_charset_info, static sp_head *
(const uchar *)name, namelen, sp_find_cached_procedure(THD *thd, char *name, uint namelen)
n, len) == 0) {
break; return (sp_head*)hash_search(thd->sp_hash+TYPE_ENUM_PROCEDURE-1,
} (const byte*)name,namelen);
return sp;
} }
...@@ -53,15 +53,13 @@ bool ...@@ -53,15 +53,13 @@ bool
sp_function_exists(THD *thd, LEX_STRING *name); sp_function_exists(THD *thd, LEX_STRING *name);
// QQ More temporary stuff until the real cache is implemented. This is // This is needed since we have to read the functions before we
// needed since we have to read the functions before we do anything else. // do anything else.
void void
sp_add_fun_to_lex(LEX *lex, LEX_STRING fun); sp_add_fun_to_lex(LEX *lex, LEX_STRING fun);
void void
sp_merge_funs(LEX *dst, LEX *src); sp_merge_funs(LEX *dst, LEX *src);
int int
sp_cache_functions(THD *thd, LEX *lex); sp_cache_functions(THD *thd, LEX *lex);
void
sp_clear_function_cache(THD *thd);
#endif /* _SP_H_ */ #endif /* _SP_H_ */
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
#include <sp_rcontext.h> #include <sp_rcontext.h>
byte *hash_get_key_for_sp_head(const byte*,uint*,my_bool);
/* /*
The following is used to initialise Table_ident with a internal The following is used to initialise Table_ident with a internal
table name table name
...@@ -155,6 +157,11 @@ THD::THD():user_time(0), is_fatal_error(0), ...@@ -155,6 +157,11 @@ THD::THD():user_time(0), is_fatal_error(0),
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key, (hash_get_key) get_var_key,
(hash_free_key) free_user_var, 0); (hash_free_key) free_user_var, 0);
hash_init(sp_hash,system_charset_info,0,0,0,
hash_get_key_for_sp_head,0,0);
hash_init(sp_hash+1,system_charset_info,0,0,0,
hash_get_key_for_sp_head,0,0);
/* For user vars replication*/ /* For user vars replication*/
if (opt_bin_log) if (opt_bin_log)
...@@ -200,9 +207,6 @@ THD::THD():user_time(0), is_fatal_error(0), ...@@ -200,9 +207,6 @@ THD::THD():user_time(0), is_fatal_error(0),
pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_unlock(&LOCK_thread_count);
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
} }
/* QQ init the temporary function cache */
spfuns.empty();
} }
...@@ -261,6 +265,10 @@ void THD::change_user(void) ...@@ -261,6 +265,10 @@ void THD::change_user(void)
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0, hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key, (hash_get_key) get_var_key,
(hash_free_key) free_user_var, 0); (hash_free_key) free_user_var, 0);
hash_init(sp_hash,system_charset_info,0,0,0,
hash_get_key_for_sp_head,0,0);
hash_init(sp_hash+1,system_charset_info,0,0,0,
hash_get_key_for_sp_head,0,0);
} }
...@@ -284,6 +292,8 @@ void THD::cleanup(void) ...@@ -284,6 +292,8 @@ void THD::cleanup(void)
close_temporary_tables(this); close_temporary_tables(this);
delete_dynamic(&user_var_events); delete_dynamic(&user_var_events);
hash_free(&user_vars); hash_free(&user_vars);
hash_free(sp_hash);
hash_free(sp_hash+1);
if (global_read_lock) if (global_read_lock)
unlock_global_read_lock(this); unlock_global_read_lock(this);
if (ull) if (ull)
...@@ -294,9 +304,6 @@ void THD::cleanup(void) ...@@ -294,9 +304,6 @@ void THD::cleanup(void)
ull= 0; ull= 0;
} }
// extern void sp_clear_function_cache(THD *);
// sp_clear_function_cache(this);
cleanup_done=1; cleanup_done=1;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -551,7 +551,7 @@ public: ...@@ -551,7 +551,7 @@ public:
bool prepare_command; bool prepare_command;
bool tmp_table_used; bool tmp_table_used;
sp_rcontext *spcont; // SP runtime context sp_rcontext *spcont; // SP runtime context
List<sp_head> spfuns; // SP FUNCTIONs HASH sp_hash[2]; // hash for SP PROCEDURES and FUNCTIONS
/* /*
If we do a purge of binary logs, log index info of the threads If we do a purge of binary logs, log index info of the threads
......
...@@ -1527,13 +1527,6 @@ restore_user: ...@@ -1527,13 +1527,6 @@ restore_user:
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
/*
Clear the SP function cache after each statement (QQ this is a temporary
solution; caching will be rehacked later).
Note: Must do this before we free_root.
*/
sp_clear_function_cache(thd);
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC)); free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -2829,7 +2822,6 @@ mysql_execute_command(THD *thd) ...@@ -2829,7 +2822,6 @@ mysql_execute_command(THD *thd)
sp_head *sph= sp_find_function(thd, &lex->udf.name); sp_head *sph= sp_find_function(thd, &lex->udf.name);
if (sph) if (sph)
{ {
delete sph; // QQ Free memory. Remove this when caching!!!
net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str); net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
goto error; goto error;
} }
...@@ -3033,18 +3025,12 @@ mysql_execute_command(THD *thd) ...@@ -3033,18 +3025,12 @@ mysql_execute_command(THD *thd)
{ {
case SP_OK: case SP_OK:
send_ok(thd); send_ok(thd);
delete lex->sphead; // QQ Free memory. Remove this when caching!!!
lex->sphead= NULL;
break; break;
case SP_WRITE_ROW_FAILED: case SP_WRITE_ROW_FAILED:
net_printf(thd, ER_SP_ALREADY_EXISTS, SP_TYPE_STRING(lex), name); net_printf(thd, ER_SP_ALREADY_EXISTS, SP_TYPE_STRING(lex), name);
delete lex->sphead; // QQ Free memory. Remove this when caching!!!
lex->sphead= NULL;
goto error; goto error;
default: default:
net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name); net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name);
delete lex->sphead; // QQ Free memory. Remove this when caching!!!
lex->sphead= NULL;
goto error; goto error;
} }
break; break;
...@@ -3068,7 +3054,6 @@ mysql_execute_command(THD *thd) ...@@ -3068,7 +3054,6 @@ mysql_execute_command(THD *thd)
if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) || if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
(res= open_and_lock_tables(thd, tables)))) (res= open_and_lock_tables(thd, tables))))
{ {
delete sp; // Free memory. Remove this when caching!!!
break; break;
} }
fix_tables_pointers(lex->all_selects_list); fix_tables_pointers(lex->all_selects_list);
...@@ -3087,7 +3072,6 @@ mysql_execute_command(THD *thd) ...@@ -3087,7 +3072,6 @@ mysql_execute_command(THD *thd)
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
#endif #endif
delete sp; // QQ Free memory. Remove this when caching!!!
goto error; goto error;
} }
smrx= thd->server_status & SERVER_MORE_RESULTS_EXISTS; smrx= thd->server_status & SERVER_MORE_RESULTS_EXISTS;
...@@ -3105,8 +3089,6 @@ mysql_execute_command(THD *thd) ...@@ -3105,8 +3089,6 @@ mysql_execute_command(THD *thd)
thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS; thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
} }
delete sp; // QQ Free memory. Remove this when caching!!!
if (res == 0) if (res == 0)
send_ok(thd); send_ok(thd);
else else
...@@ -3132,7 +3114,6 @@ mysql_execute_command(THD *thd) ...@@ -3132,7 +3114,6 @@ mysql_execute_command(THD *thd)
{ {
/* QQ This is an no-op right now, since we haven't /* QQ This is an no-op right now, since we haven't
put the characteristics in yet. */ put the characteristics in yet. */
delete sp; // QQ Free memory. Remove this when caching!!!
send_ok(thd); send_ok(thd);
} }
break; break;
......
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