1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Fix for BUG#12228: SP cache code:

* Cleanup SP Cache code, now SP Cache only deletes sp_head objects in 
  sp_cache_flush_obsolete() invalidates all pointers to routines in the cache.
* Use new SP Cache use contract in the code.

There is no test case because it doesn't seem to be possible to cause thread races to end
the same way they end in heavy-load test. This patch removes the crash in heavy test.
This commit is contained in:
sergefp@mysql.com
2005-08-08 23:23:34 +00:00
parent 56b91a8c15
commit c6db76b076
9 changed files with 196 additions and 154 deletions

View File

@ -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,86 +103,119 @@ 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.
*/
void sp_cache_insert(sp_cache **cp, sp_head *sp)
{
sp_cache *c= *cp;
if (! c)
c= new sp_cache();
if (c)
{
ulong v;
c= new sp_cache();
pthread_mutex_lock(&Cversion_lock); // LOCK
v= Cversion;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
if (c->version < v)
{
if (*cp)
c->remove_all();
c->version= v;
}
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;
pthread_mutex_lock(&Cversion_lock); // LOCK
v= 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)
{
sp_cache *c= *cp;
bool found= FALSE;
if (c)
{
ulong v;
pthread_mutex_lock(&Cversion_lock); // LOCK
v= Cversion++;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
if (c->version < v)
c->remove_all();
else
found= c->remove(name->m_qname.str, name->m_qname.length);
c->version= v+1;
}
return found;
}
void
sp_cache_invalidate()
/*
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
Cversion++;
pthread_mutex_unlock(&Cversion_lock); // UNLOCK
}
/*
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;
if (c)
{
ulong v;
pthread_mutex_lock(&Cversion_lock); // LOCK
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();
c->version= v;
}
}
}
/*************************************************************************
Internal functions
*************************************************************************/
static byte *
hash_get_key_for_sp_head(const byte *ptr, uint *plen,
my_bool first)
@ -136,7 +230,6 @@ static void
hash_free_sp_head(void *p)
{
sp_head *sp= (sp_head *)p;
delete sp;
}