~jlukas79/+junk/mysql-server

« back to all changes in this revision

Viewing changes to mysys/my_safehash.c

manual merge 6.0-main --> 6.0-bka-review

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2003-2007 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; either version 2 of the License, or
 
6
   (at your option) any later version.
 
7
 
 
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.
 
12
 
 
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 */
 
16
 
 
17
/*
 
18
  Handling of multiple key caches
 
19
 
 
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
 
22
  the cache.
 
23
*/
 
24
 
 
25
#include "mysys_priv.h"
 
26
#include <m_string.h>
 
27
#include "my_safehash.h"
 
28
 
 
29
/*****************************************************************************
 
30
  General functions to handle SAFE_HASH objects.
 
31
 
 
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
 
35
  purposes
 
36
 
 
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
*****************************************************************************/
 
40
 
 
41
 
 
42
/*
 
43
  Free a SAFE_HASH_ENTRY
 
44
 
 
45
  SYNOPSIS
 
46
    safe_hash_entry_free()
 
47
    entry                The entry which should be freed
 
48
 
 
49
  NOTE
 
50
    This function is called by the hash object on delete
 
51
*/
 
52
 
 
53
static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
 
54
{
 
55
  DBUG_ENTER("safe_hash_entry_free");
 
56
  my_free((uchar*) entry, MYF(0));
 
57
  DBUG_VOID_RETURN;
 
58
}
 
59
 
 
60
 
 
61
/*
 
62
  Get key and length for a SAFE_HASH_ENTRY
 
63
 
 
64
  SYNOPSIS
 
65
    safe_hash_entry_get()
 
66
    entry                The entry for which the key should be returned
 
67
    length               Length of the key
 
68
 
 
69
  RETURN
 
70
    #  reference on the key
 
71
*/
 
72
 
 
73
static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
 
74
                                  my_bool not_used __attribute__((unused)))
 
75
{
 
76
  *length= entry->length;
 
77
  return (uchar*) entry->key;
 
78
}
 
79
 
 
80
 
 
81
/*
 
82
  Init a SAFE_HASH object
 
83
 
 
84
  SYNOPSIS
 
85
    safe_hash_init()
 
86
    hash                safe_hash handler
 
87
    elements            Expected max number of elements
 
88
    default_value       default value
 
89
 
 
90
  NOTES
 
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.
 
93
 
 
94
  RETURN
 
95
    0  OK
 
96
    1  error
 
97
*/
 
98
 
 
99
my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
 
100
                       uchar *default_value)
 
101
{
 
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))
 
106
  {
 
107
    hash->default_value= 0;
 
108
    DBUG_RETURN(1);
 
109
  }
 
110
  my_rwlock_init(&hash->mutex, 0);
 
111
  hash->default_value= default_value;
 
112
  hash->root= 0;
 
113
  DBUG_RETURN(0);
 
114
}
 
115
 
 
116
 
 
117
/*
 
118
  Free a SAFE_HASH object
 
119
 
 
120
  SYNOPSIS
 
121
    safe_hash_free()
 
122
    hash                 Hash handle
 
123
 
 
124
  NOTES
 
125
    This is safe to call on any object that has been sent to safe_hash_init()
 
126
*/
 
127
 
 
128
void safe_hash_free(SAFE_HASH *hash)
 
129
{
 
130
  /*
 
131
    Test if safe_hash_init succeeded. This will also guard us against multiple
 
132
    free calls.
 
133
  */
 
134
  if (hash->default_value)
 
135
  {
 
136
    hash_free(&hash->hash);
 
137
    rwlock_destroy(&hash->mutex);
 
138
    hash->default_value=0;
 
139
  }
 
140
}
 
141
 
 
142
 
 
143
/*
 
144
  Return the value stored for a key or default value if no key
 
145
 
 
146
  SYNOPSIS
 
147
    safe_hash_search()
 
148
    hash                 Hash handle
 
149
    key                  key (path to table etc..)
 
150
    length               Length of key
 
151
    def                  Default value of data
 
152
 
 
153
  RETURN
 
154
    #  data associated with the key of default value if data was not found
 
155
*/
 
156
 
 
157
uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length,
 
158
                        uchar *def)
 
159
{
 
160
  uchar *result;
 
161
  DBUG_ENTER("safe_hash_search");
 
162
  rw_rdlock(&hash->mutex);
 
163
  result= hash_search(&hash->hash, key, length);
 
164
  rw_unlock(&hash->mutex);
 
165
  if (!result)
 
166
    result= def;
 
167
  else
 
168
    result= ((SAFE_HASH_ENTRY*) result)->data;
 
169
  DBUG_PRINT("exit",("data: %p", result));
 
170
  DBUG_RETURN(result);
 
171
}
 
172
 
 
173
 
 
174
/*
 
175
  Associate a key with some data
 
176
 
 
177
  SYNOPSIS
 
178
    safe_hash_set()
 
179
    hash                 Hash handle
 
180
    key                  key (path to table etc..)
 
181
    length               Length of key
 
182
    data                 data to to associate with the data
 
183
 
 
184
  NOTES
 
185
    This can be used both to insert a new entry and change an existing
 
186
    entry.
 
187
    If one associates a key with the default key cache, the key is deleted
 
188
 
 
189
  RETURN
 
190
    0  OK
 
191
    1  error (Can only be EOM). In this case my_message() is called.
 
192
*/
 
193
 
 
194
my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
 
195
                      uchar *data)
 
196
{
 
197
  SAFE_HASH_ENTRY *entry;
 
198
  my_bool error= 0;
 
199
  DBUG_ENTER("safe_hash_set");
 
200
  DBUG_PRINT("enter",("key: %.*s  data: 0x%lx", length, key, (long) data));
 
201
 
 
202
  rw_wrlock(&hash->mutex);
 
203
  entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
 
204
 
 
205
  if (data == hash->default_value)
 
206
  {
 
207
    /*
 
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
 
211
    */
 
212
    if (!entry)          /* nothing to do */
 
213
      goto end;
 
214
    /* unlink entry from list */
 
215
    if ((*entry->prev= entry->next))
 
216
      entry->next->prev= entry->prev;
 
217
    hash_delete(&hash->hash, (uchar*) entry);
 
218
    goto end;
 
219
  }
 
220
  if (entry)
 
221
  {
 
222
    /* Entry existed;  Just change the pointer to point at the new data */
 
223
    entry->data= data;
 
224
  }
 
225
  else
 
226
  {
 
227
    if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
 
228
                                               MYF(MY_WME))))
 
229
    {
 
230
      error= 1;
 
231
      goto end;
 
232
    }
 
233
    entry->key= (uchar*) (entry +1);
 
234
    memcpy((char*) entry->key, (char*) key, length);
 
235
    entry->length= length;
 
236
    entry->data= data;
 
237
    /* Link entry to list */
 
238
    if ((entry->next= hash->root))
 
239
      entry->next->prev= &entry->next;
 
240
    entry->prev= &hash->root;
 
241
    hash->root= entry;
 
242
    if (my_hash_insert(&hash->hash, (uchar*) entry))
 
243
    {
 
244
      /* This can only happen if hash got out of memory */
 
245
      my_free((char*) entry, MYF(0));
 
246
      error= 1;
 
247
      goto end;
 
248
    }
 
249
  }
 
250
 
 
251
end:
 
252
  rw_unlock(&hash->mutex);
 
253
  DBUG_RETURN(error);
 
254
}
 
255
 
 
256
 
 
257
/*
 
258
  Change all entries with one data value to another data value
 
259
 
 
260
  SYNOPSIS
 
261
    safe_hash_change()
 
262
    hash                 Hash handle
 
263
    old_data             Old data
 
264
    new_data             Change all 'old_data' to this
 
265
 
 
266
  NOTES
 
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
 
269
    default value.
 
270
*/
 
271
 
 
272
void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
 
273
{
 
274
  SAFE_HASH_ENTRY *entry, *next;
 
275
  DBUG_ENTER("safe_hash_change");
 
276
 
 
277
  rw_wrlock(&hash->mutex);
 
278
 
 
279
  for (entry= hash->root ; entry ; entry= next)
 
280
  {
 
281
    next= entry->next;
 
282
    if (entry->data == old_data)
 
283
    {
 
284
      if (new_data == hash->default_value)
 
285
      {
 
286
        if ((*entry->prev= entry->next))
 
287
          entry->next->prev= entry->prev;
 
288
        hash_delete(&hash->hash, (uchar*) entry);
 
289
      }
 
290
      else
 
291
        entry->data= new_data;
 
292
    }
 
293
  }
 
294
 
 
295
  rw_unlock(&hash->mutex);
 
296
  DBUG_VOID_RETURN;
 
297
}