1
/* Copyright (C) 2003 MySQL AB
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.
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.
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 */
17
Handling of multiple key caches
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
24
#include <drizzled/global.h>
25
#include <mysys/mysys_err.h>
26
#include <mysys/my_sys.h>
28
#include <mysys/hash.h>
29
#include <mystrings/m_string.h>
31
/*****************************************************************************
32
General functions to handle SAFE_HASH objects.
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
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
*****************************************************************************/
44
Struct to store a key and pointer to object
47
typedef struct st_safe_hash_entry
52
struct st_safe_hash_entry *next, **prev;
56
typedef struct st_safe_hash_with_default
58
pthread_rwlock_t mutex;
60
unsigned char *default_value;
61
SAFE_HASH_ENTRY *root;
66
Free a SAFE_HASH_ENTRY
68
This function is called by the hash object on delete
72
void safe_hash_entry_free(void *entry);
74
void safe_hash_entry_free(void *entry)
81
/* Get key and length for a SAFE_HASH_ENTRY */
83
static unsigned char *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
87
*length=entry->length;
88
return (unsigned char*) entry->key;
93
Init a SAFE_HASH object
97
hash safe_hash handler
98
elements Expected max number of elements
99
default_value default value
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.
110
static bool safe_hash_init(SAFE_HASH *hash, uint32_t elements,
111
unsigned char *default_value)
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))
117
hash->default_value= 0;
120
pthread_rwlock_init(&hash->mutex, 0);
121
hash->default_value= default_value;
128
Free a SAFE_HASH object
131
This is safe to call on any object that has been sent to safe_hash_init()
134
static void safe_hash_free(SAFE_HASH *hash)
137
Test if safe_hash_init succeeded. This will also guard us against multiple
140
if (hash->default_value)
142
hash_free(&hash->hash);
143
pthread_rwlock_destroy(&hash->mutex);
144
hash->default_value=0;
149
Return the value stored for a key or default value if no key
152
static unsigned char *safe_hash_search(SAFE_HASH *hash, const unsigned char *key, uint32_t length)
154
unsigned char *result;
155
pthread_rwlock_rdlock(&hash->mutex);
156
result= hash_search(&hash->hash, key, length);
157
pthread_rwlock_unlock(&hash->mutex);
159
result= hash->default_value;
161
result= ((SAFE_HASH_ENTRY*) result)->data;
167
Associate a key with some data
172
key key (path to table etc..)
174
data data to to associate with the data
177
This can be used both to insert a new entry and change an existing
179
If one associates a key with the default key cache, the key is deleted
183
1 error (Can only be EOM). In this case my_message() is called.
186
static bool safe_hash_set(SAFE_HASH *hash, const unsigned char *key, uint32_t length,
189
SAFE_HASH_ENTRY *entry;
192
pthread_rwlock_wrlock(&hash->mutex);
193
entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
195
if (data == hash->default_value)
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
202
if (!entry) /* nothing to do */
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);
212
/* Entry existed; Just change the pointer to point at the new data */
217
if (!(entry= (SAFE_HASH_ENTRY *) malloc(sizeof(*entry) + length)))
222
entry->key= (unsigned char*) (entry +1);
223
memcpy(entry->key, key, length);
224
entry->length= length;
226
/* Link entry to list */
227
if ((entry->next= hash->root))
228
entry->next->prev= &entry->next;
229
entry->prev= &hash->root;
231
if (my_hash_insert(&hash->hash, (unsigned char*) entry))
233
/* This can only happen if hash got out of memory */
241
pthread_rwlock_unlock(&hash->mutex);
247
Change all entres with one data value to another data value
253
new_data Change all 'old_data' to this
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
261
static void safe_hash_change(SAFE_HASH *hash, unsigned char *old_data, unsigned char *new_data)
263
SAFE_HASH_ENTRY *entry, *next;
265
pthread_rwlock_wrlock(&hash->mutex);
267
for (entry= hash->root ; entry ; entry= next)
270
if (entry->data == old_data)
272
if (new_data == hash->default_value)
274
if ((*entry->prev= entry->next))
275
entry->next->prev= entry->prev;
276
hash_delete(&hash->hash, (unsigned char*) entry);
279
entry->data= new_data;
283
pthread_rwlock_unlock(&hash->mutex);
288
/*****************************************************************************
289
Functions to handle the key cache objects
290
*****************************************************************************/
292
/* Variable to store all key cache objects */
293
static SAFE_HASH key_cache_hash;
296
bool multi_keycache_init(void)
298
return safe_hash_init(&key_cache_hash, 16, (unsigned char*) dflt_key_cache);
302
void multi_keycache_free(void)
304
safe_hash_free(&key_cache_hash);
308
Get a key cache to be used for a specific table.
311
multi_key_cache_search()
312
key key to find (usually table path)
313
uint32_t length Length of key.
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.
324
KEY_CACHE *multi_key_cache_search(unsigned char *key, uint32_t length)
326
if (!key_cache_hash.hash.records)
327
return dflt_key_cache;
328
return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
333
Assosiate a key cache with a key
337
multi_key_cache_set()
338
key key (path to table etc..)
340
key_cache cache to assococite with the table
343
This can be used both to insert a new entry and change an existing
348
bool multi_key_cache_set(const unsigned char *key, uint32_t length,
349
KEY_CACHE *key_cache)
351
return safe_hash_set(&key_cache_hash, key, length, (unsigned char*) key_cache);
355
void multi_key_cache_change(KEY_CACHE *old_data,
358
safe_hash_change(&key_cache_hash, (unsigned char*) old_data, (unsigned char*) new_data);