~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/mf_keycaches.cc

  • Committer: Brian Aker
  • Date: 2009-07-31 05:38:13 UTC
  • mto: (1106.3.2 heap)
  • mto: This revision was merged to the branch mainline in revision 1108.
  • Revision ID: brian@gaz-20090731053813-nip58z7ng0qux5oh
Remove multi key cache

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
 
  pthread_rwlock_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
 
extern "C"
72
 
void safe_hash_entry_free(void *entry);
73
 
 
74
 
void safe_hash_entry_free(void *entry)
75
 
{
76
 
  free(entry);
77
 
  return;
78
 
}
79
 
 
80
 
 
81
 
/* Get key and length for a SAFE_HASH_ENTRY */
82
 
 
83
 
static unsigned char *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
84
 
                                  bool not_used)
85
 
{
86
 
  (void)not_used;
87
 
  *length=entry->length;
88
 
  return (unsigned char*) entry->key;
89
 
}
90
 
 
91
 
 
92
 
/*
93
 
  Init a SAFE_HASH object
94
 
 
95
 
  SYNOPSIS
96
 
    safe_hash_init()
97
 
    hash                safe_hash handler
98
 
    elements            Expected max number of elements
99
 
    default_value       default value
100
 
 
101
 
  NOTES
102
 
    In case of error we set hash->default_value to 0 to allow one to call
103
 
    safe_hash_free on an object that couldn't be initialized.
104
 
 
105
 
  RETURN
106
 
    0  ok
107
 
    1  error
108
 
*/
109
 
 
110
 
static bool safe_hash_init(SAFE_HASH *hash, uint32_t elements,
111
 
                              unsigned char *default_value)
112
 
{
113
 
  if (hash_init(&hash->hash, &my_charset_bin, elements,
114
 
                0, 0, (hash_get_key) safe_hash_entry_get,
115
 
                safe_hash_entry_free, 0))
116
 
  {
117
 
    hash->default_value= 0;
118
 
    return(1);
119
 
  }
120
 
  pthread_rwlock_init(&hash->mutex, 0);
121
 
  hash->default_value= default_value;
122
 
  hash->root= 0;
123
 
  return(0);
124
 
}
125
 
 
126
 
 
127
 
/*
128
 
  Free a SAFE_HASH object
129
 
 
130
 
  NOTES
131
 
    This is safe to call on any object that has been sent to safe_hash_init()
132
 
*/
133
 
 
134
 
static void safe_hash_free(SAFE_HASH *hash)
135
 
{
136
 
  /*
137
 
    Test if safe_hash_init succeeded. This will also guard us against multiple
138
 
    free calls.
139
 
  */
140
 
  if (hash->default_value)
141
 
  {
142
 
    hash_free(&hash->hash);
143
 
    pthread_rwlock_destroy(&hash->mutex);
144
 
    hash->default_value=0;
145
 
  }
146
 
}
147
 
 
148
 
/*
149
 
  Return the value stored for a key or default value if no key
150
 
*/
151
 
 
152
 
static unsigned char *safe_hash_search(SAFE_HASH *hash, const unsigned char *key, uint32_t length)
153
 
{
154
 
  unsigned char *result;
155
 
  pthread_rwlock_rdlock(&hash->mutex);
156
 
  result= hash_search(&hash->hash, key, length);
157
 
  pthread_rwlock_unlock(&hash->mutex);
158
 
  if (!result)
159
 
    result= hash->default_value;
160
 
  else
161
 
    result= ((SAFE_HASH_ENTRY*) result)->data;
162
 
  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 bool safe_hash_set(SAFE_HASH *hash, const unsigned char *key, uint32_t length,
187
 
                             unsigned char *data)
188
 
{
189
 
  SAFE_HASH_ENTRY *entry;
190
 
  bool error= 0;
191
 
 
192
 
  pthread_rwlock_wrlock(&hash->mutex);
193
 
  entry= (SAFE_HASH_ENTRY*) 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
 
    hash_delete(&hash->hash, (unsigned char*) 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 *) malloc(sizeof(*entry) + length)))
218
 
    {
219
 
      error= 1;
220
 
      goto end;
221
 
    }
222
 
    entry->key= (unsigned char*) (entry +1);
223
 
    memcpy(entry->key, key, length);
224
 
    entry->length= length;
225
 
    entry->data= data;
226
 
    /* Link entry to list */
227
 
    if ((entry->next= hash->root))
228
 
      entry->next->prev= &entry->next;
229
 
    entry->prev= &hash->root;
230
 
    hash->root= entry;
231
 
    if (my_hash_insert(&hash->hash, (unsigned char*) entry))
232
 
    {
233
 
      /* This can only happen if hash got out of memory */
234
 
      free((char*) entry);
235
 
      error= 1;
236
 
      goto end;
237
 
    }
238
 
  }
239
 
 
240
 
end:
241
 
  pthread_rwlock_unlock(&hash->mutex);
242
 
  return(error);
243
 
}
244
 
 
245
 
 
246
 
/*
247
 
  Change all entres with one data value to another data value
248
 
 
249
 
  SYONOPSIS
250
 
    safe_hash_change()
251
 
    hash                        Hash handle
252
 
    old_data                    Old data
253
 
    new_data                    Change all 'old_data' to this
254
 
 
255
 
  NOTES
256
 
    We use the linked list to traverse all elements in the hash as
257
 
    this allows us to delete elements in the case where 'new_data' is the
258
 
    default value.
259
 
*/
260
 
 
261
 
static void safe_hash_change(SAFE_HASH *hash, unsigned char *old_data, unsigned char *new_data)
262
 
{
263
 
  SAFE_HASH_ENTRY *entry, *next;
264
 
 
265
 
  pthread_rwlock_wrlock(&hash->mutex);
266
 
 
267
 
  for (entry= hash->root ; entry ; entry= next)
268
 
  {
269
 
    next= entry->next;
270
 
    if (entry->data == old_data)
271
 
    {
272
 
      if (new_data == hash->default_value)
273
 
      {
274
 
        if ((*entry->prev= entry->next))
275
 
          entry->next->prev= entry->prev;
276
 
        hash_delete(&hash->hash, (unsigned char*) entry);
277
 
      }
278
 
      else
279
 
        entry->data= new_data;
280
 
    }
281
 
  }
282
 
 
283
 
  pthread_rwlock_unlock(&hash->mutex);
284
 
  return;
285
 
}
286
 
 
287
 
 
288
 
/*****************************************************************************
289
 
  Functions to handle the key cache objects
290
 
*****************************************************************************/
291
 
 
292
 
/* Variable to store all key cache objects */
293
 
static SAFE_HASH key_cache_hash;
294
 
 
295
 
 
296
 
bool multi_keycache_init(void)
297
 
{
298
 
  return safe_hash_init(&key_cache_hash, 16, (unsigned char*) dflt_key_cache);
299
 
}
300
 
 
301
 
 
302
 
void multi_keycache_free(void)
303
 
{
304
 
  safe_hash_free(&key_cache_hash);
305
 
}
306
 
 
307
 
/*
308
 
  Get a key cache to be used for a specific table.
309
 
 
310
 
  SYNOPSIS
311
 
    multi_key_cache_search()
312
 
    key                         key to find (usually table path)
313
 
    uint32_t length                     Length of key.
314
 
 
315
 
  NOTES
316
 
    This function is coded in such a way that we will return the
317
 
    default key cache even if one never called multi_keycache_init.
318
 
    This will ensure that it works with old MyISAM clients.
319
 
 
320
 
  RETURN
321
 
    key cache to use
322
 
*/
323
 
 
324
 
KEY_CACHE *multi_key_cache_search(unsigned char *key, uint32_t length)
325
 
{
326
 
  if (!key_cache_hash.hash.records)
327
 
    return dflt_key_cache;
328
 
  return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
329
 
}
330
 
 
331
 
 
332
 
/*
333
 
  Assosiate a key cache with a key
334
 
 
335
 
 
336
 
  SYONOPSIS
337
 
    multi_key_cache_set()
338
 
    key                         key (path to table etc..)
339
 
    length                      Length of key
340
 
    key_cache                   cache to assococite with the table
341
 
 
342
 
  NOTES
343
 
    This can be used both to insert a new entry and change an existing
344
 
    entry
345
 
*/
346
 
 
347
 
 
348
 
bool multi_key_cache_set(const unsigned char *key, uint32_t length,
349
 
                            KEY_CACHE *key_cache)
350
 
{
351
 
  return safe_hash_set(&key_cache_hash, key, length, (unsigned char*) key_cache);
352
 
}
353
 
 
354
 
 
355
 
void multi_key_cache_change(KEY_CACHE *old_data,
356
 
                            KEY_CACHE *new_data)
357
 
{
358
 
  safe_hash_change(&key_cache_hash, (unsigned char*) old_data, (unsigned char*) new_data);
359
 
}