1
/* Copyright (C) 2003-2007 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; either version 2 of the License, or
6
(at your option) any later version.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
Handling of multiple key caches
20
The idea is to have a thread safe hash on the table name,
21
with a default key cache value that is returned if the table name is not in
25
#include "mysys_priv.h"
27
#include "my_safehash.h"
29
/*****************************************************************************
30
General functions to handle SAFE_HASH objects.
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
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
*****************************************************************************/
43
Free a SAFE_HASH_ENTRY
46
safe_hash_entry_free()
47
entry The entry which should be freed
50
This function is called by the hash object on delete
53
static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
55
DBUG_ENTER("safe_hash_entry_free");
56
my_free((uchar*) entry, MYF(0));
62
Get key and length for a SAFE_HASH_ENTRY
66
entry The entry for which the key should be returned
67
length Length of the key
70
# reference on the key
73
static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
74
my_bool not_used __attribute__((unused)))
76
*length= entry->length;
77
return (uchar*) entry->key;
82
Init a SAFE_HASH object
86
hash safe_hash handler
87
elements Expected max number of elements
88
default_value default value
91
In case of error we set hash->default_value to 0 to allow one to call
92
safe_hash_free on an object that couldn't be initialized.
99
my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
100
uchar *default_value)
102
DBUG_ENTER("safe_hash_init");
103
if (hash_init(&hash->hash, &my_charset_bin, elements,
104
0, 0, (hash_get_key) safe_hash_entry_get,
105
(void (*)(void*)) safe_hash_entry_free, 0))
107
hash->default_value= 0;
110
my_rwlock_init(&hash->mutex, 0);
111
hash->default_value= default_value;
118
Free a SAFE_HASH object
125
This is safe to call on any object that has been sent to safe_hash_init()
128
void safe_hash_free(SAFE_HASH *hash)
131
Test if safe_hash_init succeeded. This will also guard us against multiple
134
if (hash->default_value)
136
hash_free(&hash->hash);
137
rwlock_destroy(&hash->mutex);
138
hash->default_value=0;
144
Return the value stored for a key or default value if no key
149
key key (path to table etc..)
151
def Default value of data
154
# data associated with the key of default value if data was not found
157
uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length,
161
DBUG_ENTER("safe_hash_search");
162
rw_rdlock(&hash->mutex);
163
result= hash_search(&hash->hash, key, length);
164
rw_unlock(&hash->mutex);
168
result= ((SAFE_HASH_ENTRY*) result)->data;
169
DBUG_PRINT("exit",("data: %p", result));
175
Associate a key with some data
180
key key (path to table etc..)
182
data data to to associate with the data
185
This can be used both to insert a new entry and change an existing
187
If one associates a key with the default key cache, the key is deleted
191
1 error (Can only be EOM). In this case my_message() is called.
194
my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
197
SAFE_HASH_ENTRY *entry;
199
DBUG_ENTER("safe_hash_set");
200
DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
202
rw_wrlock(&hash->mutex);
203
entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
205
if (data == hash->default_value)
208
The key is to be associated with the default entry. In this case
209
we can just delete the entry (if it existed) from the hash as a
210
search will return the default entry
212
if (!entry) /* nothing to do */
214
/* unlink entry from list */
215
if ((*entry->prev= entry->next))
216
entry->next->prev= entry->prev;
217
hash_delete(&hash->hash, (uchar*) entry);
222
/* Entry existed; Just change the pointer to point at the new data */
227
if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
233
entry->key= (uchar*) (entry +1);
234
memcpy((char*) entry->key, (char*) key, length);
235
entry->length= length;
237
/* Link entry to list */
238
if ((entry->next= hash->root))
239
entry->next->prev= &entry->next;
240
entry->prev= &hash->root;
242
if (my_hash_insert(&hash->hash, (uchar*) entry))
244
/* This can only happen if hash got out of memory */
245
my_free((char*) entry, MYF(0));
252
rw_unlock(&hash->mutex);
258
Change all entries with one data value to another data value
264
new_data Change all 'old_data' to this
267
We use the linked list to traverse all elements in the hash as
268
this allows us to delete elements in the case where 'new_data' is the
272
void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
274
SAFE_HASH_ENTRY *entry, *next;
275
DBUG_ENTER("safe_hash_change");
277
rw_wrlock(&hash->mutex);
279
for (entry= hash->root ; entry ; entry= next)
282
if (entry->data == old_data)
284
if (new_data == hash->default_value)
286
if ((*entry->prev= entry->next))
287
entry->next->prev= entry->prev;
288
hash_delete(&hash->hash, (uchar*) entry);
291
entry->data= new_data;
295
rw_unlock(&hash->mutex);