summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorsergefp@mysql.com <>2005-08-10 21:17:52 +0000
committersergefp@mysql.com <>2005-08-10 21:17:52 +0000
commit9125477df54aff3f7cdaf64637f5867cc8a8d75d (patch)
tree7cf1a45d0722c48c30871c34d564241d5bf84dad /sql
parent8392a814af9c80c7c6b8c1a4819b278e43a7e93d (diff)
parentfbab5fc5685076a43f52f55a1633207709ef953c (diff)
downloadmariadb-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.cc16
-rw-r--r--sql/sp_cache.cc202
-rw-r--r--sql/sp_cache.h101
-rw-r--r--sql/sql_parse.cc3
-rw-r--r--sql/sql_prepare.cc6
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);