00001 /* Copyright (C) 2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /* 00018 Handling of multiple key caches 00019 00020 The idea is to have a thread safe hash on the table name, 00021 with a default key cache value that is returned if the table name is not in 00022 the cache. 00023 */ 00024 00025 #include "mysys_priv.h" 00026 #include <keycache.h> 00027 #include <hash.h> 00028 #include <m_string.h> 00029 00030 /***************************************************************************** 00031 General functions to handle SAFE_HASH objects. 00032 00033 A SAFE_HASH object is used to store the hash, the mutex and default value 00034 needed by the rest of the key cache code. 00035 This is a separate struct to make it easy to later reuse the code for other 00036 purposes 00037 00038 All entries are linked in a list to allow us to traverse all elements 00039 and delete selected ones. (HASH doesn't allow any easy ways to do this). 00040 *****************************************************************************/ 00041 00042 /* 00043 Struct to store a key and pointer to object 00044 */ 00045 00046 typedef struct st_safe_hash_entry 00047 { 00048 byte *key; 00049 uint length; 00050 byte *data; 00051 struct st_safe_hash_entry *next, **prev; 00052 } SAFE_HASH_ENTRY; 00053 00054 00055 typedef struct st_safe_hash_with_default 00056 { 00057 #ifdef THREAD 00058 rw_lock_t mutex; 00059 #endif 00060 HASH hash; 00061 byte *default_value; 00062 SAFE_HASH_ENTRY *root; 00063 } SAFE_HASH; 00064 00065 00066 /* 00067 Free a SAFE_HASH_ENTRY 00068 00069 This function is called by the hash object on delete 00070 */ 00071 00072 static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry) 00073 { 00074 DBUG_ENTER("free_assign_entry"); 00075 my_free((gptr) entry, MYF(0)); 00076 DBUG_VOID_RETURN; 00077 } 00078 00079 00080 /* Get key and length for a SAFE_HASH_ENTRY */ 00081 00082 static byte *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, uint *length, 00083 my_bool not_used __attribute__((unused))) 00084 { 00085 *length=entry->length; 00086 return (byte*) entry->key; 00087 } 00088 00089 00090 /* 00091 Init a SAFE_HASH object 00092 00093 SYNOPSIS 00094 safe_hash_init() 00095 hash safe_hash handler 00096 elements Expected max number of elements 00097 default_value default value 00098 00099 NOTES 00100 In case of error we set hash->default_value to 0 to allow one to call 00101 safe_hash_free on an object that couldn't be initialized. 00102 00103 RETURN 00104 0 ok 00105 1 error 00106 */ 00107 00108 static my_bool safe_hash_init(SAFE_HASH *hash, uint elements, 00109 byte *default_value) 00110 { 00111 DBUG_ENTER("safe_hash"); 00112 if (hash_init(&hash->hash, &my_charset_bin, elements, 00113 0, 0, (hash_get_key) safe_hash_entry_get, 00114 (void (*)(void*)) safe_hash_entry_free, 0)) 00115 { 00116 hash->default_value= 0; 00117 DBUG_RETURN(1); 00118 } 00119 my_rwlock_init(&hash->mutex, 0); 00120 hash->default_value= default_value; 00121 hash->root= 0; 00122 DBUG_RETURN(0); 00123 } 00124 00125 00126 /* 00127 Free a SAFE_HASH object 00128 00129 NOTES 00130 This is safe to call on any object that has been sent to safe_hash_init() 00131 */ 00132 00133 static void safe_hash_free(SAFE_HASH *hash) 00134 { 00135 /* 00136 Test if safe_hash_init succeeded. This will also guard us against multiple 00137 free calls. 00138 */ 00139 if (hash->default_value) 00140 { 00141 hash_free(&hash->hash); 00142 rwlock_destroy(&hash->mutex); 00143 hash->default_value=0; 00144 } 00145 } 00146 00147 /* 00148 Return the value stored for a key or default value if no key 00149 */ 00150 00151 static byte *safe_hash_search(SAFE_HASH *hash, const byte *key, uint length) 00152 { 00153 byte *result; 00154 DBUG_ENTER("safe_hash_search"); 00155 rw_rdlock(&hash->mutex); 00156 result= hash_search(&hash->hash, key, length); 00157 rw_unlock(&hash->mutex); 00158 if (!result) 00159 result= hash->default_value; 00160 else 00161 result= ((SAFE_HASH_ENTRY*) result)->data; 00162 DBUG_PRINT("exit",("data: 0x%lx", result)); 00163 DBUG_RETURN(result); 00164 } 00165 00166 00167 /* 00168 Associate a key with some data 00169 00170 SYONOPSIS 00171 safe_hash_set() 00172 hash Hash handle 00173 key key (path to table etc..) 00174 length Length of key 00175 data data to to associate with the data 00176 00177 NOTES 00178 This can be used both to insert a new entry and change an existing 00179 entry. 00180 If one associates a key with the default key cache, the key is deleted 00181 00182 RETURN 00183 0 ok 00184 1 error (Can only be EOM). In this case my_message() is called. 00185 */ 00186 00187 static my_bool safe_hash_set(SAFE_HASH *hash, const byte *key, uint length, 00188 byte *data) 00189 { 00190 SAFE_HASH_ENTRY *entry; 00191 my_bool error= 0; 00192 DBUG_ENTER("safe_hash_set"); 00193 DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, data)); 00194 00195 rw_wrlock(&hash->mutex); 00196 entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length); 00197 00198 if (data == hash->default_value) 00199 { 00200 /* 00201 The key is to be associated with the default entry. In this case 00202 we can just delete the entry (if it existed) from the hash as a 00203 search will return the default entry 00204 */ 00205 if (!entry) /* nothing to do */ 00206 goto end; 00207 /* unlink entry from list */ 00208 if ((*entry->prev= entry->next)) 00209 entry->next->prev= entry->prev; 00210 hash_delete(&hash->hash, (byte*) entry); 00211 goto end; 00212 } 00213 if (entry) 00214 { 00215 /* Entry existed; Just change the pointer to point at the new data */ 00216 entry->data= data; 00217 } 00218 else 00219 { 00220 if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length, 00221 MYF(MY_WME)))) 00222 { 00223 error= 1; 00224 goto end; 00225 } 00226 entry->key= (byte*) (entry +1); 00227 memcpy((char*) entry->key, (char*) key, length); 00228 entry->length= length; 00229 entry->data= data; 00230 /* Link entry to list */ 00231 if ((entry->next= hash->root)) 00232 entry->next->prev= &entry->next; 00233 entry->prev= &hash->root; 00234 hash->root= entry; 00235 if (my_hash_insert(&hash->hash, (byte*) entry)) 00236 { 00237 /* This can only happen if hash got out of memory */ 00238 my_free((char*) entry, MYF(0)); 00239 error= 1; 00240 goto end; 00241 } 00242 } 00243 00244 end: 00245 rw_unlock(&hash->mutex); 00246 DBUG_RETURN(error); 00247 } 00248 00249 00250 /* 00251 Change all entres with one data value to another data value 00252 00253 SYONOPSIS 00254 safe_hash_change() 00255 hash Hash handle 00256 old_data Old data 00257 new_data Change all 'old_data' to this 00258 00259 NOTES 00260 We use the linked list to traverse all elements in the hash as 00261 this allows us to delete elements in the case where 'new_data' is the 00262 default value. 00263 */ 00264 00265 static void safe_hash_change(SAFE_HASH *hash, byte *old_data, byte *new_data) 00266 { 00267 SAFE_HASH_ENTRY *entry, *next; 00268 DBUG_ENTER("safe_hash_set"); 00269 00270 rw_wrlock(&hash->mutex); 00271 00272 for (entry= hash->root ; entry ; entry= next) 00273 { 00274 next= entry->next; 00275 if (entry->data == old_data) 00276 { 00277 if (new_data == hash->default_value) 00278 { 00279 if ((*entry->prev= entry->next)) 00280 entry->next->prev= entry->prev; 00281 hash_delete(&hash->hash, (byte*) entry); 00282 } 00283 else 00284 entry->data= new_data; 00285 } 00286 } 00287 00288 rw_unlock(&hash->mutex); 00289 DBUG_VOID_RETURN; 00290 } 00291 00292 00293 /***************************************************************************** 00294 Functions to handle the key cache objects 00295 *****************************************************************************/ 00296 00297 /* Variable to store all key cache objects */ 00298 static SAFE_HASH key_cache_hash; 00299 00300 00301 my_bool multi_keycache_init(void) 00302 { 00303 return safe_hash_init(&key_cache_hash, 16, (byte*) dflt_key_cache); 00304 } 00305 00306 00307 void multi_keycache_free(void) 00308 { 00309 safe_hash_free(&key_cache_hash); 00310 } 00311 00312 /* 00313 Get a key cache to be used for a specific table. 00314 00315 SYNOPSIS 00316 multi_key_cache_search() 00317 key key to find (usually table path) 00318 uint length Length of key. 00319 00320 NOTES 00321 This function is coded in such a way that we will return the 00322 default key cache even if one never called multi_keycache_init. 00323 This will ensure that it works with old MyISAM clients. 00324 00325 RETURN 00326 key cache to use 00327 */ 00328 00329 KEY_CACHE *multi_key_cache_search(byte *key, uint length) 00330 { 00331 if (!key_cache_hash.hash.records) 00332 return dflt_key_cache; 00333 return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length); 00334 } 00335 00336 00337 /* 00338 Assosiate a key cache with a key 00339 00340 00341 SYONOPSIS 00342 multi_key_cache_set() 00343 key key (path to table etc..) 00344 length Length of key 00345 key_cache cache to assococite with the table 00346 00347 NOTES 00348 This can be used both to insert a new entry and change an existing 00349 entry 00350 */ 00351 00352 00353 my_bool multi_key_cache_set(const byte *key, uint length, 00354 KEY_CACHE *key_cache) 00355 { 00356 return safe_hash_set(&key_cache_hash, key, length, (byte*) key_cache); 00357 } 00358 00359 00360 void multi_key_cache_change(KEY_CACHE *old_data, 00361 KEY_CACHE *new_data) 00362 { 00363 safe_hash_change(&key_cache_hash, (byte*) old_data, (byte*) new_data); 00364 }
1.4.7

