~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mf_keycaches.c

Merged from Toru - removal of my_time_t.

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
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
  pthread_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
    pthread_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
  pthread_rwlock_rdlock(&hash->mutex);
 
152
  result= hash_search(&hash->hash, key, length);
 
153
  pthread_rwlock_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
  pthread_rwlock_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 *) malloc(sizeof(*entry) + length)))
 
214
    {
 
215
      error= 1;
 
216
      goto end;
 
217
    }
 
218
    entry->key= (unsigned char*) (entry +1);
 
219
    memcpy(entry->key, key, length);
 
220
    entry->length= length;
 
221
    entry->data= data;
 
222
    /* Link entry to list */
 
223
    if ((entry->next= hash->root))
 
224
      entry->next->prev= &entry->next;
 
225
    entry->prev= &hash->root;
 
226
    hash->root= entry;
 
227
    if (my_hash_insert(&hash->hash, (unsigned char*) entry))
 
228
    {
 
229
      /* This can only happen if hash got out of memory */
 
230
      free((char*) entry);
 
231
      error= 1;
 
232
      goto end;
 
233
    }
 
234
  }
 
235
 
 
236
end:
 
237
  pthread_rwlock_unlock(&hash->mutex);
 
238
  return(error);
 
239
}
 
240
 
 
241
 
 
242
/*
 
243
  Change all entres with one data value to another data value
 
244
 
 
245
  SYONOPSIS
 
246
    safe_hash_change()
 
247
    hash                        Hash handle
 
248
    old_data                    Old data
 
249
    new_data                    Change all 'old_data' to this
 
250
 
 
251
  NOTES
 
252
    We use the linked list to traverse all elements in the hash as
 
253
    this allows us to delete elements in the case where 'new_data' is the
 
254
    default value.
 
255
*/
 
256
 
 
257
static void safe_hash_change(SAFE_HASH *hash, unsigned char *old_data, unsigned char *new_data)
 
258
{
 
259
  SAFE_HASH_ENTRY *entry, *next;
 
260
 
 
261
  pthread_rwlock_wrlock(&hash->mutex);
 
262
 
 
263
  for (entry= hash->root ; entry ; entry= next)
 
264
  {
 
265
    next= entry->next;
 
266
    if (entry->data == old_data)
 
267
    {
 
268
      if (new_data == hash->default_value)
 
269
      {
 
270
        if ((*entry->prev= entry->next))
 
271
          entry->next->prev= entry->prev;
 
272
        hash_delete(&hash->hash, (unsigned char*) entry);
 
273
      }
 
274
      else
 
275
        entry->data= new_data;
 
276
    }
 
277
  }
 
278
 
 
279
  pthread_rwlock_unlock(&hash->mutex);
 
280
  return;
 
281
}
 
282
 
 
283
 
 
284
/*****************************************************************************
 
285
  Functions to handle the key cache objects
 
286
*****************************************************************************/
 
287
 
 
288
/* Variable to store all key cache objects */
 
289
static SAFE_HASH key_cache_hash;
 
290
 
 
291
 
 
292
bool multi_keycache_init(void)
 
293
{
 
294
  return safe_hash_init(&key_cache_hash, 16, (unsigned char*) dflt_key_cache);
 
295
}
 
296
 
 
297
 
 
298
void multi_keycache_free(void)
 
299
{
 
300
  safe_hash_free(&key_cache_hash);
 
301
}
 
302
 
 
303
/*
 
304
  Get a key cache to be used for a specific table.
 
305
 
 
306
  SYNOPSIS
 
307
    multi_key_cache_search()
 
308
    key                         key to find (usually table path)
 
309
    uint32_t length                     Length of key.
 
310
 
 
311
  NOTES
 
312
    This function is coded in such a way that we will return the
 
313
    default key cache even if one never called multi_keycache_init.
 
314
    This will ensure that it works with old MyISAM clients.
 
315
 
 
316
  RETURN
 
317
    key cache to use
 
318
*/
 
319
 
 
320
KEY_CACHE *multi_key_cache_search(unsigned char *key, uint32_t length)
 
321
{
 
322
  if (!key_cache_hash.hash.records)
 
323
    return dflt_key_cache;
 
324
  return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
 
325
}
 
326
 
 
327
 
 
328
/*
 
329
  Assosiate a key cache with a key
 
330
 
 
331
 
 
332
  SYONOPSIS
 
333
    multi_key_cache_set()
 
334
    key                         key (path to table etc..)
 
335
    length                      Length of key
 
336
    key_cache                   cache to assococite with the table
 
337
 
 
338
  NOTES
 
339
    This can be used both to insert a new entry and change an existing
 
340
    entry
 
341
*/
 
342
 
 
343
 
 
344
bool multi_key_cache_set(const unsigned char *key, uint32_t length,
 
345
                            KEY_CACHE *key_cache)
 
346
{
 
347
  return safe_hash_set(&key_cache_hash, key, length, (unsigned char*) key_cache);
 
348
}
 
349
 
 
350
 
 
351
void multi_key_cache_change(KEY_CACHE *old_data,
 
352
                            KEY_CACHE *new_data)
 
353
{
 
354
  safe_hash_change(&key_cache_hash, (unsigned char*) old_data, (unsigned char*) new_data);
 
355
}