diff options
Diffstat (limited to 'sql/sp_cache.cc')
-rw-r--r-- | sql/sp_cache.cc | 224 |
1 files changed, 160 insertions, 64 deletions
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index c8f0ed6ba2d..495f969eeac 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -22,16 +22,80 @@ #include "sp_head.h" static pthread_mutex_t Cversion_lock; -static ulong Cversion = 0; +static ulong volatile 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; @@ -42,114 +106,145 @@ sp_cache_clear(sp_cache **cp) } } -void -sp_cache_insert(sp_cache **cp, sp_head *sp) -{ - sp_cache *c= *cp; - if (! c) - c= new sp_cache(); - if (c) - { - ulong v; +/* + Insert a routine into the cache. - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK + 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) +*/ - if (c->version < v) - { - if (*cp) - c->remove_all(); - c->version= v; - } - c->insert(sp); - if (*cp == NULL) - *cp= c; +void sp_cache_insert(sp_cache **cp, sp_head *sp) +{ + sp_cache *c; + ulong v; + + if (!(c= *cp)) + { + if (!(c= new sp_cache())) + return; // End of memory error + c->version= Cversion; // No need to lock when reading long variable } + DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, + sp->m_qname.str)); + c->insert(sp); + *cp= c; // Update *cp if it was NULL } -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) return NULL; + return c->lookup(name->m_qname.str, name->m_qname.length); +} - 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); +/* + 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")); + thread_safe_increment(Cversion, &Cversion_lock); } -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++; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - + v= Cversion; // No need to lock when reading long variable 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 -} -static byte * -hash_get_key_for_sp_head(const byte *ptr, uint *plen, +/************************************************************************* + Internal functions + *************************************************************************/ + +static byte *hash_get_key_for_sp_head(const byte *ptr, uint *plen, my_bool first) { sp_head *sp= (sp_head *)ptr; - *plen= sp->m_qname.length; return (byte*) sp->m_qname.str; } + static void hash_free_sp_head(void *p) { sp_head *sp= (sp_head *)p; - delete sp; } + sp_cache::sp_cache() { init(); } + sp_cache::~sp_cache() { hash_free(&m_hashtable); } + void sp_cache::init() { @@ -158,6 +253,7 @@ sp_cache::init() version= 0; } + void sp_cache::cleanup() { |