MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sp_cache.cc
1 /* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 #include "sql_priv.h"
17 #include "unireg.h"
18 #include "sp_cache.h"
19 #include "sp_head.h"
20 
21 static mysql_mutex_t Cversion_lock;
22 static ulong volatile Cversion= 0;
23 
24 
25 /*
26  Cache of stored routines.
27 */
28 
29 class sp_cache
30 {
31 public:
32  sp_cache();
33  ~sp_cache();
34 
42  inline bool insert(sp_head *sp)
43  {
44  return my_hash_insert(&m_hashtable, (const uchar *)sp);
45  }
46 
47  inline sp_head *lookup(char *name, uint namelen)
48  {
49  return (sp_head *) my_hash_search(&m_hashtable, (const uchar *)name,
50  namelen);
51  }
52 
53  inline void remove(sp_head *sp)
54  {
55  my_hash_delete(&m_hashtable, (uchar *)sp);
56  }
57 
65  void enforce_limit(ulong upper_limit_for_elements)
66  {
67  if (m_hashtable.records > upper_limit_for_elements)
68  my_hash_reset(&m_hashtable);
69  }
70 
71 private:
72  void init();
73  void cleanup();
74 
75  /* All routines in this cache */
76  HASH m_hashtable;
77 }; // class sp_cache
78 
79 #ifdef HAVE_PSI_INTERFACE
80 static PSI_mutex_key key_Cversion_lock;
81 
82 static PSI_mutex_info all_sp_cache_mutexes[]=
83 {
84  { &key_Cversion_lock, "Cversion_lock", PSI_FLAG_GLOBAL}
85 };
86 
87 static void init_sp_cache_psi_keys(void)
88 {
89  const char* category= "sql";
90  int count;
91 
92  count= array_elements(all_sp_cache_mutexes);
93  mysql_mutex_register(category, all_sp_cache_mutexes, count);
94 }
95 #endif
96 
97 /* Initialize the SP caching once at startup */
98 
99 void sp_cache_init()
100 {
101 #ifdef HAVE_PSI_INTERFACE
102  init_sp_cache_psi_keys();
103 #endif
104 
105  mysql_mutex_init(key_Cversion_lock, &Cversion_lock, MY_MUTEX_INIT_FAST);
106 }
107 
108 
109 /*
110  Clear the cache *cp and set *cp to NULL.
111 
112  SYNOPSIS
113  sp_cache_clear()
114  cp Pointer to cache to clear
115 
116  NOTE
117  This function doesn't invalidate other caches.
118 */
119 
120 void sp_cache_clear(sp_cache **cp)
121 {
122  sp_cache *c= *cp;
123 
124  if (c)
125  {
126  delete c;
127  *cp= NULL;
128  }
129 }
130 
131 
132 /*
133  Insert a routine into the cache.
134 
135  SYNOPSIS
136  sp_cache_insert()
137  cp The cache to put routine into
138  sp Routine to insert.
139 
140  TODO: Perhaps it will be more straightforward if in case we returned an
141  error from this function when we couldn't allocate sp_cache. (right
142  now failure to put routine into cache will cause a 'SP not found'
143  error to be reported at some later time)
144 */
145 
146 void sp_cache_insert(sp_cache **cp, sp_head *sp)
147 {
148  sp_cache *c;
149 
150  if (!(c= *cp))
151  {
152  if (!(c= new sp_cache()))
153  return; // End of memory error
154  }
155  /* Reading a ulong variable with no lock. */
156  sp->set_sp_cache_version(Cversion);
157  DBUG_PRINT("info",("sp_cache: inserting: %.*s", (int) sp->m_qname.length,
158  sp->m_qname.str));
159  c->insert(sp);
160  *cp= c; // Update *cp if it was NULL
161 }
162 
163 
164 /*
165  Look up a routine in the cache.
166  SYNOPSIS
167  sp_cache_lookup()
168  cp Cache to look into
169  name Name of rutine to find
170 
171  NOTE
172  An obsolete (but not more obsolete then since last
173  sp_cache_flush_obsolete call) routine may be returned.
174 
175  RETURN
176  The routine or
177  NULL if the routine not found.
178 */
179 
180 sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name)
181 {
182  sp_cache *c= *cp;
183  if (! c)
184  return NULL;
185  return c->lookup(name->m_qname.str, name->m_qname.length);
186 }
187 
188 
189 /*
190  Invalidate all routines in all caches.
191 
192  SYNOPSIS
193  sp_cache_invalidate()
194 
195  NOTE
196  This is called when a VIEW definition is created or modified (and in some
197  other contexts). We can't destroy sp_head objects here as one may modify
198  VIEW definitions from prelocking-free SPs.
199 */
200 
201 void sp_cache_invalidate()
202 {
203  DBUG_PRINT("info",("sp_cache: invalidating"));
204  thread_safe_increment(Cversion, &Cversion_lock);
205 }
206 
207 
219 void sp_cache_flush_obsolete(sp_cache **cp, sp_head **sp)
220 {
221  if ((*sp)->sp_cache_version() < Cversion && !(*sp)->is_invoked())
222  {
223  (*cp)->remove(*sp);
224  *sp= NULL;
225  }
226 }
227 
228 
233 ulong sp_cache_version()
234 {
235  return Cversion;
236 }
237 
238 
247 void
248 sp_cache_enforce_limit(sp_cache *c, ulong upper_limit_for_elements)
249 {
250  if (c)
251  c->enforce_limit(upper_limit_for_elements);
252 }
253 
254 /*************************************************************************
255  Internal functions
256  *************************************************************************/
257 
258 extern "C" uchar *hash_get_key_for_sp_head(const uchar *ptr, size_t *plen,
259  my_bool first);
260 extern "C" void hash_free_sp_head(void *p);
261 
262 uchar *hash_get_key_for_sp_head(const uchar *ptr, size_t *plen,
263  my_bool first)
264 {
265  sp_head *sp= (sp_head *)ptr;
266  *plen= sp->m_qname.length;
267  return (uchar*) sp->m_qname.str;
268 }
269 
270 
271 void hash_free_sp_head(void *p)
272 {
273  sp_head *sp= (sp_head *)p;
274  delete sp;
275 }
276 
277 
278 sp_cache::sp_cache()
279 {
280  init();
281 }
282 
283 
284 sp_cache::~sp_cache()
285 {
286  my_hash_free(&m_hashtable);
287 }
288 
289 
290 void
291 sp_cache::init()
292 {
293  my_hash_init(&m_hashtable, system_charset_info, 0, 0, 0,
294  hash_get_key_for_sp_head, hash_free_sp_head, 0);
295 }
296 
297 
298 void
299 sp_cache::cleanup()
300 {
301  my_hash_free(&m_hashtable);
302 }