~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mf_keycaches.c

MergedĀ inĀ trunk.

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 <drizzled/global.h>
25
 
#include <mysys/mysys_err.h>
26
 
#include <mysys/my_sys.h>
27
 
#include <keycache.h>
28
 
#include <mysys/hash.h>
29
 
#include <mystrings/m_string.h>
30
 
 
31
 
/*****************************************************************************
32
 
  General functions to handle SAFE_HASH objects.
33
 
 
34
 
  A SAFE_HASH object is used to store the hash, the mutex and default value
35
 
  needed by the rest of the key cache code.
36
 
  This is a separate struct to make it easy to later reuse the code for other
37
 
  purposes
38
 
 
39
 
  All entries are linked in a list to allow us to traverse all elements
40
 
  and delete selected ones. (HASH doesn't allow any easy ways to do this).
41
 
*****************************************************************************/
42
 
 
43
 
/*
44
 
  Struct to store a key and pointer to object
45
 
*/
46
 
 
47
 
typedef struct st_safe_hash_entry
48
 
{
49
 
  unsigned char *key;
50
 
  uint32_t length;
51
 
  unsigned char *data;
52
 
  struct st_safe_hash_entry *next, **prev;
53
 
} SAFE_HASH_ENTRY;
54
 
 
55
 
 
56
 
typedef struct st_safe_hash_with_default
57
 
{
58
 
  rw_lock_t mutex;
59
 
  HASH hash;
60
 
  unsigned char *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
 
  free((unsigned char*) entry);
74
 
  return;
75
 
}
76
 
 
77
 
 
78
 
/* Get key and length for a SAFE_HASH_ENTRY */
79
 
 
80
 
static unsigned char *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
81
 
                                  bool not_used __attribute__((unused)))
82
 
{
83
 
  *length=entry->length;
84
 
  return (unsigned char*) entry->key;
85
 
}
86
 
 
87
 
 
88
 
/*
89
 
  Init a SAFE_HASH object
90
 
 
91
 
  SYNOPSIS
92
 
    safe_hash_init()
93
 
    hash                safe_hash handler
94
 
    elements            Expected max number of elements
95
 
    default_value       default value
96
 
 
97
 
  NOTES
98
 
    In case of error we set hash->default_value to 0 to allow one to call
99
 
    safe_hash_free on an object that couldn't be initialized.
100
 
 
101
 
  RETURN
102
 
    0  ok
103
 
    1  error
104
 
*/
105
 
 
106
 
static bool safe_hash_init(SAFE_HASH *hash, uint32_t elements,
107
 
                              unsigned char *default_value)
108
 
{
109
 
  if (hash_init(&hash->hash, &my_charset_bin, elements,
110
 
                0, 0, (hash_get_key) safe_hash_entry_get,
111
 
                (void (*)(void*)) safe_hash_entry_free, 0))
112
 
  {
113
 
    hash->default_value= 0;
114
 
    return(1);
115
 
  }
116
 
  my_rwlock_init(&hash->mutex, 0);
117
 
  hash->default_value= default_value;
118
 
  hash->root= 0;
119
 
  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
 
    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 unsigned char *safe_hash_search(SAFE_HASH *hash, const unsigned char *key, uint32_t length)
149
 
{
150
 
  unsigned char *result;
151
 
  rw_rdlock(&hash->mutex);
152
 
  result= hash_search(&hash->hash, key, length);
153
 
  rw_unlock(&hash->mutex);
154
 
  if (!result)
155
 
    result= hash->default_value;
156
 
  else
157
 
    result= ((SAFE_HASH_ENTRY*) result)->data;
158
 
  return(result);
159
 
}
160
 
 
161
 
 
162
 
/*
163
 
  Associate a key with some data
164
 
 
165
 
  SYONOPSIS
166
 
    safe_hash_set()
167
 
    hash                        Hash handle
168
 
    key                         key (path to table etc..)
169
 
    length                      Length of key
170
 
    data                        data to to associate with the data
171
 
 
172
 
  NOTES
173
 
    This can be used both to insert a new entry and change an existing
174
 
    entry.
175
 
    If one associates a key with the default key cache, the key is deleted
176
 
 
177
 
  RETURN
178
 
    0  ok
179
 
    1  error (Can only be EOM). In this case my_message() is called.
180
 
*/
181
 
 
182
 
static bool safe_hash_set(SAFE_HASH *hash, const unsigned char *key, uint32_t length,
183
 
                             unsigned char *data)
184
 
{
185
 
  SAFE_HASH_ENTRY *entry;
186
 
  bool error= 0;
187
 
 
188
 
  rw_wrlock(&hash->mutex);
189
 
  entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
190
 
 
191
 
  if (data == hash->default_value)
192
 
  {
193
 
    /*
194
 
      The key is to be associated with the default entry. In this case
195
 
      we can just delete the entry (if it existed) from the hash as a
196
 
      search will return the default entry
197
 
    */
198
 
    if (!entry)                                 /* nothing to do */
199
 
      goto end;
200
 
    /* unlink entry from list */
201
 
    if ((*entry->prev= entry->next))
202
 
      entry->next->prev= entry->prev;
203
 
    hash_delete(&hash->hash, (unsigned char*) entry);
204
 
    goto end;
205
 
  }
206
 
  if (entry)
207
 
  {
208
 
    /* Entry existed;  Just change the pointer to point at the new data */
209
 
    entry->data= data;
210
 
  }
211
 
  else
212
 
  {
213
 
    if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
214
 
                                               MYF(MY_WME))))
215
 
    {
216
 
      error= 1;
217
 
      goto end;
218
 
    }
219
 
    entry->key= (unsigned char*) (entry +1);
220
 
    memcpy(entry->key, key, length);
221
 
    entry->length= length;
222
 
    entry->data= data;
223
 
    /* Link entry to list */
224
 
    if ((entry->next= hash->root))
225
 
      entry->next->prev= &entry->next;
226
 
    entry->prev= &hash->root;
227
 
    hash->root= entry;
228
 
    if (my_hash_insert(&hash->hash, (unsigned char*) entry))
229
 
    {
230
 
      /* This can only happen if hash got out of memory */
231
 
      free((char*) entry);
232
 
      error= 1;
233
 
      goto end;
234
 
    }
235
 
  }
236
 
 
237
 
end:
238
 
  rw_unlock(&hash->mutex);
239
 
  return(error);
240
 
}
241
 
 
242
 
 
243
 
/*
244
 
  Change all entres with one data value to another data value
245
 
 
246
 
  SYONOPSIS
247
 
    safe_hash_change()
248
 
    hash                        Hash handle
249
 
    old_data                    Old data
250
 
    new_data                    Change all 'old_data' to this
251
 
 
252
 
  NOTES
253
 
    We use the linked list to traverse all elements in the hash as
254
 
    this allows us to delete elements in the case where 'new_data' is the
255
 
    default value.
256
 
*/
257
 
 
258
 
static void safe_hash_change(SAFE_HASH *hash, unsigned char *old_data, unsigned char *new_data)
259
 
{
260
 
  SAFE_HASH_ENTRY *entry, *next;
261
 
 
262
 
  rw_wrlock(&hash->mutex);
263
 
 
264
 
  for (entry= hash->root ; entry ; entry= next)
265
 
  {
266
 
    next= entry->next;
267
 
    if (entry->data == old_data)
268
 
    {
269
 
      if (new_data == hash->default_value)
270
 
      {
271
 
        if ((*entry->prev= entry->next))
272
 
          entry->next->prev= entry->prev;
273
 
        hash_delete(&hash->hash, (unsigned char*) entry);
274
 
      }
275
 
      else
276
 
        entry->data= new_data;
277
 
    }
278
 
  }
279
 
 
280
 
  rw_unlock(&hash->mutex);
281
 
  return;
282
 
}
283
 
 
284
 
 
285
 
/*****************************************************************************
286
 
  Functions to handle the key cache objects
287
 
*****************************************************************************/
288
 
 
289
 
/* Variable to store all key cache objects */
290
 
static SAFE_HASH key_cache_hash;
291
 
 
292
 
 
293
 
bool multi_keycache_init(void)
294
 
{
295
 
  return safe_hash_init(&key_cache_hash, 16, (unsigned char*) dflt_key_cache);
296
 
}
297
 
 
298
 
 
299
 
void multi_keycache_free(void)
300
 
{
301
 
  safe_hash_free(&key_cache_hash);
302
 
}
303
 
 
304
 
/*
305
 
  Get a key cache to be used for a specific table.
306
 
 
307
 
  SYNOPSIS
308
 
    multi_key_cache_search()
309
 
    key                         key to find (usually table path)
310
 
    uint32_t length                     Length of key.
311
 
 
312
 
  NOTES
313
 
    This function is coded in such a way that we will return the
314
 
    default key cache even if one never called multi_keycache_init.
315
 
    This will ensure that it works with old MyISAM clients.
316
 
 
317
 
  RETURN
318
 
    key cache to use
319
 
*/
320
 
 
321
 
KEY_CACHE *multi_key_cache_search(unsigned char *key, uint32_t length)
322
 
{
323
 
  if (!key_cache_hash.hash.records)
324
 
    return dflt_key_cache;
325
 
  return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
326
 
}
327
 
 
328
 
 
329
 
/*
330
 
  Assosiate a key cache with a key
331
 
 
332
 
 
333
 
  SYONOPSIS
334
 
    multi_key_cache_set()
335
 
    key                         key (path to table etc..)
336
 
    length                      Length of key
337
 
    key_cache                   cache to assococite with the table
338
 
 
339
 
  NOTES
340
 
    This can be used both to insert a new entry and change an existing
341
 
    entry
342
 
*/
343
 
 
344
 
 
345
 
bool multi_key_cache_set(const unsigned char *key, uint32_t length,
346
 
                            KEY_CACHE *key_cache)
347
 
{
348
 
  return safe_hash_set(&key_cache_hash, key, length, (unsigned char*) key_cache);
349
 
}
350
 
 
351
 
 
352
 
void multi_key_cache_change(KEY_CACHE *old_data,
353
 
                            KEY_CACHE *new_data)
354
 
{
355
 
  safe_hash_change(&key_cache_hash, (unsigned char*) old_data, (unsigned char*) new_data);
356
 
}