~ubuntu-branches/ubuntu/precise/mysql-5.5/precise-201203300109

« back to all changes in this revision

Viewing changes to mysys/mf_keycaches.c

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2011-11-08 11:31:13 UTC
  • Revision ID: package-import@ubuntu.com-20111108113113-3ulw01fvi4vn8m25
Tags: upstream-5.5.17
ImportĀ upstreamĀ versionĀ 5.5.17

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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;
 
51
} SAFE_HASH_ENTRY;
 
52
 
 
53
 
 
54
typedef struct st_safe_hash_with_default
 
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
{
 
187
  SAFE_HASH_ENTRY *entry;
 
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
}