~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to mysys/mf_keycaches.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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