MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mf_keycaches.c
1 /* Copyright (c) 2003, 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
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /*
17  Handling of multiple key caches
18 
19  The idea is to have a thread safe hash on the table name,
20  with a default key cache value that is returned if the table name is not in
21  the cache.
22 */
23 
24 #include "mysys_priv.h"
25 #include <keycache.h>
26 #include <hash.h>
27 #include <m_string.h>
28 
29 /*****************************************************************************
30  General functions to handle SAFE_HASH objects.
31 
32  A SAFE_HASH object is used to store the hash, the mutex and default value
33  needed by the rest of the key cache code.
34  This is a separate struct to make it easy to later reuse the code for other
35  purposes
36 
37  All entries are linked in a list to allow us to traverse all elements
38  and delete selected ones. (HASH doesn't allow any easy ways to do this).
39 *****************************************************************************/
40 
41 /*
42  Struct to store a key and pointer to object
43 */
44 
45 typedef struct st_safe_hash_entry
46 {
47  uchar *key;
48  uint length;
49  uchar *data;
50  struct st_safe_hash_entry *next, **prev;
52 
53 
55 {
56  rw_lock_t mutex;
57  HASH hash;
58  uchar *default_value;
59  SAFE_HASH_ENTRY *root;
60 } SAFE_HASH;
61 
62 
63 /*
64  Free a SAFE_HASH_ENTRY
65 
66  This function is called by the hash object on delete
67 */
68 
69 static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
70 {
71  DBUG_ENTER("free_assign_entry");
72  my_free(entry);
73  DBUG_VOID_RETURN;
74 }
75 
76 
77 /* Get key and length for a SAFE_HASH_ENTRY */
78 
79 static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
80  my_bool not_used __attribute__((unused)))
81 {
82  *length=entry->length;
83  return (uchar*) entry->key;
84 }
85 
86 
87 /*
88  Init a SAFE_HASH object
89 
90  SYNOPSIS
91  safe_hash_init()
92  hash safe_hash handler
93  elements Expected max number of elements
94  default_value default value
95 
96  NOTES
97  In case of error we set hash->default_value to 0 to allow one to call
98  safe_hash_free on an object that couldn't be initialized.
99 
100  RETURN
101  0 ok
102  1 error
103 */
104 
105 static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
106  uchar *default_value)
107 {
108  DBUG_ENTER("safe_hash");
109  if (my_hash_init(&hash->hash, &my_charset_bin, elements,
110  0, 0, (my_hash_get_key) safe_hash_entry_get,
111  (void (*)(void*)) safe_hash_entry_free, 0))
112  {
113  hash->default_value= 0;
114  DBUG_RETURN(1);
115  }
116  my_rwlock_init(&hash->mutex, 0);
117  hash->default_value= default_value;
118  hash->root= 0;
119  DBUG_RETURN(0);
120 }
121 
122 
123 /*
124  Free a SAFE_HASH object
125 
126  NOTES
127  This is safe to call on any object that has been sent to safe_hash_init()
128 */
129 
130 static void safe_hash_free(SAFE_HASH *hash)
131 {
132  /*
133  Test if safe_hash_init succeeded. This will also guard us against multiple
134  free calls.
135  */
136  if (hash->default_value)
137  {
138  my_hash_free(&hash->hash);
139  rwlock_destroy(&hash->mutex);
140  hash->default_value=0;
141  }
142 }
143 
144 /*
145  Return the value stored for a key or default value if no key
146 */
147 
148 static uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length)
149 {
150  uchar *result;
151  DBUG_ENTER("safe_hash_search");
152  rw_rdlock(&hash->mutex);
153  result= my_hash_search(&hash->hash, key, length);
154  rw_unlock(&hash->mutex);
155  if (!result)
156  result= hash->default_value;
157  else
158  result= ((SAFE_HASH_ENTRY*) result)->data;
159  DBUG_PRINT("exit",("data: 0x%lx", (long) result));
160  DBUG_RETURN(result);
161 }
162 
163 
164 /*
165  Associate a key with some data
166 
167  SYONOPSIS
168  safe_hash_set()
169  hash Hash handle
170  key key (path to table etc..)
171  length Length of key
172  data data to to associate with the data
173 
174  NOTES
175  This can be used both to insert a new entry and change an existing
176  entry.
177  If one associates a key with the default key cache, the key is deleted
178 
179  RETURN
180  0 ok
181  1 error (Can only be EOM). In this case my_message() is called.
182 */
183 
184 static my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
185  uchar *data)
186 {
188  my_bool error= 0;
189  DBUG_ENTER("safe_hash_set");
190  DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
191 
192  rw_wrlock(&hash->mutex);
193  entry= (SAFE_HASH_ENTRY*) my_hash_search(&hash->hash, key, length);
194 
195  if (data == hash->default_value)
196  {
197  /*
198  The key is to be associated with the default entry. In this case
199  we can just delete the entry (if it existed) from the hash as a
200  search will return the default entry
201  */
202  if (!entry) /* nothing to do */
203  goto end;
204  /* unlink entry from list */
205  if ((*entry->prev= entry->next))
206  entry->next->prev= entry->prev;
207  my_hash_delete(&hash->hash, (uchar*) entry);
208  goto end;
209  }
210  if (entry)
211  {
212  /* Entry existed; Just change the pointer to point at the new data */
213  entry->data= data;
214  }
215  else
216  {
217  if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
218  MYF(MY_WME))))
219  {
220  error= 1;
221  goto end;
222  }
223  entry->key= (uchar*) (entry +1);
224  memcpy((char*) entry->key, (char*) key, length);
225  entry->length= length;
226  entry->data= data;
227  /* Link entry to list */
228  if ((entry->next= hash->root))
229  entry->next->prev= &entry->next;
230  entry->prev= &hash->root;
231  hash->root= entry;
232  if (my_hash_insert(&hash->hash, (uchar*) entry))
233  {
234  /* This can only happen if hash got out of memory */
235  my_free(entry);
236  error= 1;
237  goto end;
238  }
239  }
240 
241 end:
242  rw_unlock(&hash->mutex);
243  DBUG_RETURN(error);
244 }
245 
246 
247 /*
248  Change all entres with one data value to another data value
249 
250  SYONOPSIS
251  safe_hash_change()
252  hash Hash handle
253  old_data Old data
254  new_data Change all 'old_data' to this
255 
256  NOTES
257  We use the linked list to traverse all elements in the hash as
258  this allows us to delete elements in the case where 'new_data' is the
259  default value.
260 */
261 
262 static void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
263 {
264  SAFE_HASH_ENTRY *entry, *next;
265  DBUG_ENTER("safe_hash_set");
266 
267  rw_wrlock(&hash->mutex);
268 
269  for (entry= hash->root ; entry ; entry= next)
270  {
271  next= entry->next;
272  if (entry->data == old_data)
273  {
274  if (new_data == hash->default_value)
275  {
276  if ((*entry->prev= entry->next))
277  entry->next->prev= entry->prev;
278  my_hash_delete(&hash->hash, (uchar*) entry);
279  }
280  else
281  entry->data= new_data;
282  }
283  }
284 
285  rw_unlock(&hash->mutex);
286  DBUG_VOID_RETURN;
287 }
288 
289 
290 /*****************************************************************************
291  Functions to handle the key cache objects
292 *****************************************************************************/
293 
294 /* Variable to store all key cache objects */
295 static SAFE_HASH key_cache_hash;
296 
297 
298 my_bool multi_keycache_init(void)
299 {
300  return safe_hash_init(&key_cache_hash, 16, (uchar*) dflt_key_cache);
301 }
302 
303 
304 void multi_keycache_free(void)
305 {
306  safe_hash_free(&key_cache_hash);
307 }
308 
309 /*
310  Get a key cache to be used for a specific table.
311 
312  SYNOPSIS
313  multi_key_cache_search()
314  key key to find (usually table path)
315  uint length Length of key.
316 
317  NOTES
318  This function is coded in such a way that we will return the
319  default key cache even if one never called multi_keycache_init.
320  This will ensure that it works with old MyISAM clients.
321 
322  RETURN
323  key cache to use
324 */
325 
326 KEY_CACHE *multi_key_cache_search(uchar *key, uint length)
327 {
328  if (!key_cache_hash.hash.records)
329  return dflt_key_cache;
330  return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
331 }
332 
333 
334 /*
335  Assosiate a key cache with a key
336 
337 
338  SYONOPSIS
339  multi_key_cache_set()
340  key key (path to table etc..)
341  length Length of key
342  key_cache cache to assococite with the table
343 
344  NOTES
345  This can be used both to insert a new entry and change an existing
346  entry
347 */
348 
349 
350 my_bool multi_key_cache_set(const uchar *key, uint length,
351  KEY_CACHE *key_cache)
352 {
353  return safe_hash_set(&key_cache_hash, key, length, (uchar*) key_cache);
354 }
355 
356 
357 void multi_key_cache_change(KEY_CACHE *old_data,
358  KEY_CACHE *new_data)
359 {
360  safe_hash_change(&key_cache_hash, (uchar*) old_data, (uchar*) new_data);
361 }