diff options
author | sergefp@mysql.com <> | 2005-08-10 21:17:52 +0000 |
---|---|---|
committer | sergefp@mysql.com <> | 2005-08-10 21:17:52 +0000 |
commit | 9125477df54aff3f7cdaf64637f5867cc8a8d75d (patch) | |
tree | 7cf1a45d0722c48c30871c34d564241d5bf84dad /sql | |
parent | 8392a814af9c80c7c6b8c1a4819b278e43a7e93d (diff) | |
parent | fbab5fc5685076a43f52f55a1633207709ef953c (diff) | |
download | mariadb-git-9125477df54aff3f7cdaf64637f5867cc8a8d75d.tar.gz |
Merge mysql.com:/home/psergey/mysql-5.0-bug12228-r4
into mysql.com:/home/psergey/mysql-5.0-bug12228-r5
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sp.cc | 16 | ||||
-rw-r--r-- | sql/sp_cache.cc | 202 | ||||
-rw-r--r-- | sql/sp_cache.h | 101 | ||||
-rw-r--r-- | sql/sql_parse.cc | 3 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 6 |
5 files changed, 184 insertions, 144 deletions
diff --git a/sql/sp.cc b/sql/sp.cc index 0eee0ac209c..5dd7c613a10 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -989,13 +989,11 @@ int sp_drop_procedure(THD *thd, sp_name *name) { int ret; - bool found; DBUG_ENTER("sp_drop_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_proc_cache, name); ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1005,13 +1003,11 @@ int sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; - bool found; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_proc_cache, name); ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, chistics); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1102,13 +1098,11 @@ int sp_drop_function(THD *thd, sp_name *name) { int ret; - bool found; DBUG_ENTER("sp_drop_function"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_func_cache, name); ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } @@ -1118,13 +1112,11 @@ int sp_update_function(THD *thd, sp_name *name, st_sp_chistics *chistics) { int ret; - bool found; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); - found= sp_cache_remove(&thd->sp_func_cache, name); ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, chistics); - if (!found && !ret) + if (!ret) sp_cache_invalidate(); DBUG_RETURN(ret); } diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index c8f0ed6ba2d..68e8dbb3252 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -24,17 +24,78 @@ static pthread_mutex_t Cversion_lock; static ulong Cversion = 0; -void -sp_cache_init() + +/* + Cache of stored routines. +*/ + +class sp_cache +{ +public: + ulong version; + + sp_cache(); + ~sp_cache(); + + inline void insert(sp_head *sp) + { + /* TODO: why don't we check return value? */ + my_hash_insert(&m_hashtable, (const byte *)sp); + } + + inline sp_head *lookup(char *name, uint namelen) + { + return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen); + } + +#ifdef NOT_USED + inline bool remove(char *name, uint namelen) + { + sp_head *sp= lookup(name, namelen); + if (sp) + { + hash_delete(&m_hashtable, (byte *)sp); + return TRUE; + } + return FALSE; + } +#endif + + inline void remove_all() + { + cleanup(); + init(); + } + +private: + void init(); + void cleanup(); + + /* All routines in this cache */ + HASH m_hashtable; +}; // class sp_cache + + +/* Initialize the SP caching once at startup */ + +void sp_cache_init() { pthread_mutex_init(&Cversion_lock, MY_MUTEX_INIT_FAST); } -void -sp_cache_clear(sp_cache **cp) + +/* + Clear the cache *cp and set *cp to NULL. + SYNOPSIS + sp_cache_clear() + cp Pointer to cache to clear + NOTE + This function doesn't invalidate other caches. +*/ + +void sp_cache_clear(sp_cache **cp) { sp_cache *c= *cp; - if (c) { delete c; @@ -42,85 +103,121 @@ sp_cache_clear(sp_cache **cp) } } -void -sp_cache_insert(sp_cache **cp, sp_head *sp) + +/* + Insert a routine into the cache. + + SYNOPSIS + sp_cache_insert() + cp The cache to put routine into + sp Routine to insert. + + TODO: Perhaps it will be more straightforward if in case we returned an + error from this function when we couldn't allocate sp_cache. (right + now failure to put routine into cache will cause a 'SP not found' + error to be reported at some later time) +*/ + +void sp_cache_insert(sp_cache **cp, sp_head *sp) { sp_cache *c= *cp; - if (! c) - c= new sp_cache(); - if (c) + if (!c && (c= new sp_cache())) { - ulong v; - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; + c->version= Cversion; pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - { - if (*cp) - c->remove_all(); - c->version= v; - } + } + if (c) + { + DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, + sp->m_qname.str)); c->insert(sp); if (*cp == NULL) *cp= c; } } -sp_head * -sp_cache_lookup(sp_cache **cp, sp_name *name) + +/* + Look up a routine in the cache. + SYNOPSIS + sp_cache_lookup() + cp Cache to look into + name Name of rutine to find + + NOTE + An obsolete (but not more obsolete then since last + sp_cache_flush_obsolete call) routine may be returned. + + RETURN + The routine or + NULL if the routine not found. +*/ + +sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name) { - ulong v; sp_cache *c= *cp; - - if (! c) + if (!c) return NULL; + return c->lookup(name->m_qname.str, name->m_qname.length); +} + + +/* + Invalidate all routines in all caches. + SYNOPSIS + sp_cache_invalidate() + + NOTE + This is called when a VIEW definition is modifed. We can't destroy sp_head + objects here as one may modify VIEW definitions from prelocking-free SPs. +*/ + +void sp_cache_invalidate() +{ + DBUG_PRINT("info",("sp_cache: invalidating")); pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; + Cversion++; pthread_mutex_unlock(&Cversion_lock); // UNLOCK - - if (c->version < v) - { - c->remove_all(); - c->version= v; - return NULL; - } - return c->lookup(name->m_qname.str, name->m_qname.length); } -bool -sp_cache_remove(sp_cache **cp, sp_name *name) + +/* + Remove out-of-date SPs from the cache. + + SYNOPSIS + sp_cache_flush_obsolete() + cp Cache to flush + + NOTE + This invalidates pointers to sp_head objects this thread uses. + In practice that means 'dont call this function when inside SP'. +*/ + +void sp_cache_flush_obsolete(sp_cache **cp) { sp_cache *c= *cp; - bool found= FALSE; - if (c) { ulong v; - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion++; + v= Cversion; pthread_mutex_unlock(&Cversion_lock); // UNLOCK - if (c->version < v) + { + DBUG_PRINT("info",("sp_cache: deleting all functions")); + /* We need to delete all elements. */ c->remove_all(); - else - found= c->remove(name->m_qname.str, name->m_qname.length); - c->version= v+1; + c->version= v; + } } - return found; } -void -sp_cache_invalidate() -{ - pthread_mutex_lock(&Cversion_lock); // LOCK - Cversion++; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK -} +/************************************************************************* + Internal functions + *************************************************************************/ static byte * hash_get_key_for_sp_head(const byte *ptr, uint *plen, @@ -136,7 +233,6 @@ static void hash_free_sp_head(void *p) { sp_head *sp= (sp_head *)p; - delete sp; } diff --git a/sql/sp_cache.h b/sql/sp_cache.h index 14b2db97f5f..1021d17b9e2 100644 --- a/sql/sp_cache.h +++ b/sql/sp_cache.h @@ -25,94 +25,39 @@ /* Stored procedures/functions cache. This is used as follows: * Each thread has its own cache. - * Each sp_head object is put into its thread cache before it is used, and + * Each sp_head object is put into its thread cache before it is used, and then remains in the cache until deleted. */ class sp_head; class sp_cache; -/* Initialize the SP caching once at startup */ -void sp_cache_init(); +/* + Cache usage scenarios: + 1. Application-wide init: + sp_cache_init(); + + 2. SP execution in thread: + 2.1 While holding sp_head* pointers: + + // look up a routine in the cache (no checks if it is up to date or not) + sp_cache_lookup(); + + sp_cache_insert(); + sp_cache_invalidate(); + + 2.2 When not holding any sp_head* pointers: + sp_cache_flush_obsolete(); + + 3. Before thread exit: + sp_cache_clear(); +*/ -/* Clear the cache *cp and set *cp to NULL */ +void sp_cache_init(); void sp_cache_clear(sp_cache **cp); - -/* Insert an SP into cache. If 'cp' points to NULL, it's set to a new cache */ void sp_cache_insert(sp_cache **cp, sp_head *sp); - -/* Lookup an SP in cache */ sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name); - -/* - Remove an SP from cache, and also bump the Cversion number so all other - caches are invalidated. - Returns true if something was removed. -*/ -bool sp_cache_remove(sp_cache **cp, sp_name *name); - -/* Invalidate all existing SP caches by bumping Cversion number. */ void sp_cache_invalidate(); - - -/* - * - * The cache class. Don't use this directly, use the C API above - * - */ - -class sp_cache -{ -public: - - ulong version; - - sp_cache(); - - ~sp_cache(); - - void - init(); - - void - cleanup(); - - inline void - insert(sp_head *sp) - { - my_hash_insert(&m_hashtable, (const byte *)sp); - } - - inline sp_head * - lookup(char *name, uint namelen) - { - return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen); - } - - inline bool - remove(char *name, uint namelen) - { - sp_head *sp= lookup(name, namelen); - - if (sp) - { - hash_delete(&m_hashtable, (byte *)sp); - return TRUE; - } - return FALSE; - } - - inline void - remove_all() - { - cleanup(); - init(); - } - -private: - - HASH m_hashtable; - -}; // class sp_cache +void sp_cache_flush_obsolete(sp_cache **cp); #endif /* _SP_CACHE_H_ */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index bc5505bb790..a0930307205 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5340,11 +5340,12 @@ void mysql_init_multi_delete(LEX *lex) void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); - mysql_init_query(thd, (uchar*) inBuf, length); if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex= thd->lex; + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); if (!yyparse((void *)thd) && ! thd->is_fatal_error) { #ifndef NO_EMBEDDED_ACCESS_CHECKS diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c196bf76dda..9d60218b285 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -73,6 +73,7 @@ Long data handling: #include <m_ctype.h> // for isspace() #include "sp_head.h" #include "sp.h" +#include "sp_cache.h" #ifdef EMBEDDED_LIBRARY /* include MYSQL_BIND headers */ #include <mysql.h> @@ -1783,6 +1784,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, lex= thd->lex; lex->safe_to_cache_query= 0; + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); + error= yyparse((void *)thd) || thd->is_fatal_error || thd->net.report_error || init_param_array(stmt); /* @@ -2060,6 +2064,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) thd->protocol= stmt->protocol; // Switch to binary protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); + sp_cache_flush_obsolete(&thd->sp_proc_cache); + sp_cache_flush_obsolete(&thd->sp_func_cache); mysql_execute_command(thd); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); |