mf_keycaches.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:9k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /*
  14.   Handling of multiple key caches
  15.   The idea is to have a thread safe hash on the table name,
  16.   with a default key cache value that is returned if the table name is not in
  17.   the cache.
  18. */
  19. #include "mysys_priv.h"
  20. #include <keycache.h>
  21. #include <hash.h>
  22. #include <m_string.h>
  23. /*****************************************************************************
  24.   General functions to handle SAFE_HASH objects.
  25.   A SAFE_HASH object is used to store the hash, the mutex and default value
  26.   needed by the rest of the key cache code.
  27.   This is a separate struct to make it easy to later reuse the code for other
  28.   purposes
  29.   All entries are linked in a list to allow us to traverse all elements
  30.   and delete selected ones. (HASH doesn't allow any easy ways to do this).
  31. *****************************************************************************/
  32. /*
  33.   Struct to store a key and pointer to object
  34. */
  35. typedef struct st_safe_hash_entry
  36. {
  37.   byte *key;
  38.   uint length;
  39.   byte *data;
  40.   struct st_safe_hash_entry *next, **prev;
  41. } SAFE_HASH_ENTRY;
  42. typedef struct st_safe_hash_with_default
  43. {
  44. #ifdef THREAD
  45.   rw_lock_t mutex;
  46. #endif
  47.   HASH hash;
  48.   byte *default_value;
  49.   SAFE_HASH_ENTRY *root;
  50. } SAFE_HASH;
  51. /*
  52.   Free a SAFE_HASH_ENTRY
  53.   This function is called by the hash object on delete
  54. */
  55. static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
  56. {
  57.   DBUG_ENTER("free_assign_entry");
  58.   my_free((gptr) entry, MYF(0));
  59.   DBUG_VOID_RETURN;
  60. }
  61. /* Get key and length for a SAFE_HASH_ENTRY */
  62. static byte *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, uint *length,
  63.  my_bool not_used __attribute__((unused)))
  64. {
  65.   *length=entry->length;
  66.   return (byte*) entry->key;
  67. }
  68. /*
  69.   Init a SAFE_HASH object
  70.   SYNOPSIS
  71.     safe_hash_init()
  72.     hash safe_hash handler
  73.     elements Expected max number of elements
  74.     default_value default value
  75.   NOTES
  76.     In case of error we set hash->default_value to 0 to allow one to call
  77.     safe_hash_free on an object that couldn't be initialized.
  78.   RETURN
  79.     0  ok
  80.     1  error
  81. */
  82. static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
  83.       byte *default_value)
  84. {
  85.   DBUG_ENTER("safe_hash");
  86.   if (hash_init(&hash->hash, &my_charset_bin, elements,
  87. 0, 0, (hash_get_key) safe_hash_entry_get,
  88. (void (*)(void*)) safe_hash_entry_free, 0))
  89.   {
  90.     hash->default_value= 0;
  91.     DBUG_RETURN(1);
  92.   }
  93.   my_rwlock_init(&hash->mutex, 0);
  94.   hash->default_value= default_value;
  95.   hash->root= 0;
  96.   DBUG_RETURN(0);
  97. }
  98. /*
  99.   Free a SAFE_HASH object
  100.   NOTES
  101.     This is safe to call on any object that has been sent to safe_hash_init()
  102. */
  103. static void safe_hash_free(SAFE_HASH *hash)
  104. {
  105.   /*
  106.     Test if safe_hash_init succeeded. This will also guard us against multiple
  107.     free calls.
  108.   */
  109.   if (hash->default_value)
  110.   {
  111.     hash_free(&hash->hash);
  112.     rwlock_destroy(&hash->mutex);
  113.     hash->default_value=0;
  114.   }
  115. }
  116. /*
  117.   Return the value stored for a key or default value if no key
  118. */
  119. static byte *safe_hash_search(SAFE_HASH *hash, const byte *key, uint length)
  120. {
  121.   byte *result;
  122.   DBUG_ENTER("safe_hash_search");
  123.   rw_rdlock(&hash->mutex);
  124.   result= hash_search(&hash->hash, key, length);
  125.   rw_unlock(&hash->mutex);
  126.   if (!result)
  127.     result= hash->default_value;
  128.   else
  129.     result= ((SAFE_HASH_ENTRY*) result)->data;
  130.   DBUG_PRINT("exit",("data: 0x%lx", result));
  131.   DBUG_RETURN(result);
  132. }
  133. /*
  134.   Associate a key with some data
  135.   SYONOPSIS
  136.     safe_hash_set()
  137.     hash Hash handle
  138.     key key (path to table etc..)
  139.     length Length of key
  140.     data data to to associate with the data
  141.   NOTES
  142.     This can be used both to insert a new entry and change an existing
  143.     entry.
  144.     If one associates a key with the default key cache, the key is deleted
  145.   RETURN
  146.     0  ok
  147.     1  error (Can only be EOM). In this case my_message() is called.
  148. */
  149. static my_bool safe_hash_set(SAFE_HASH *hash, const byte *key, uint length,
  150.      byte *data)
  151. {
  152.   SAFE_HASH_ENTRY *entry;
  153.   my_bool error= 0;
  154.   DBUG_ENTER("safe_hash_set");
  155.   DBUG_PRINT("enter",("key: %.*s  data: 0x%lx", length, key, data));
  156.   rw_wrlock(&hash->mutex);
  157.   entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
  158.   if (data == hash->default_value)
  159.   {
  160.     /*
  161.       The key is to be associated with the default entry. In this case
  162.       we can just delete the entry (if it existed) from the hash as a
  163.       search will return the default entry
  164.     */
  165.     if (!entry) /* nothing to do */
  166.       goto end;
  167.     /* unlink entry from list */
  168.     if ((*entry->prev= entry->next))
  169.       entry->next->prev= entry->prev;
  170.     hash_delete(&hash->hash, (byte*) entry);
  171.     goto end;
  172.   }
  173.   if (entry)
  174.   {
  175.     /* Entry existed;  Just change the pointer to point at the new data */
  176.     entry->data= data;
  177.   }
  178.   else
  179.   {
  180.     if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
  181.        MYF(MY_WME))))
  182.     {
  183.       error= 1;
  184.       goto end;
  185.     }
  186.     entry->key= (byte*) (entry +1);
  187.     memcpy((char*) entry->key, (char*) key, length);
  188.     entry->length= length;
  189.     entry->data= data;
  190.     /* Link entry to list */
  191.     if ((entry->next= hash->root))
  192.       entry->next->prev= &entry->next;
  193.     entry->prev= &hash->root;
  194.     hash->root= entry;
  195.     if (my_hash_insert(&hash->hash, (byte*) entry))
  196.     {
  197.       /* This can only happen if hash got out of memory */
  198.       my_free((char*) entry, MYF(0));
  199.       error= 1;
  200.       goto end;
  201.     }
  202.   }
  203. end:
  204.   rw_unlock(&hash->mutex);
  205.   DBUG_RETURN(error);
  206. }
  207. /*
  208.   Change all entres with one data value to another data value
  209.   SYONOPSIS
  210.     safe_hash_change()
  211.     hash Hash handle
  212.     old_data Old data
  213.     new_data Change all 'old_data' to this
  214.   NOTES
  215.     We use the linked list to traverse all elements in the hash as
  216.     this allows us to delete elements in the case where 'new_data' is the
  217.     default value.
  218. */
  219. static void safe_hash_change(SAFE_HASH *hash, byte *old_data, byte *new_data)
  220. {
  221.   SAFE_HASH_ENTRY *entry, *next;
  222.   DBUG_ENTER("safe_hash_set");
  223.   rw_wrlock(&hash->mutex);
  224.   for (entry= hash->root ; entry ; entry= next)
  225.   {
  226.     next= entry->next;
  227.     if (entry->data == old_data)
  228.     {
  229.       if (new_data == hash->default_value)
  230.       {
  231.         if ((*entry->prev= entry->next))
  232.           entry->next->prev= entry->prev;
  233. hash_delete(&hash->hash, (byte*) entry);
  234.       }
  235.       else
  236. entry->data= new_data;
  237.     }
  238.   }
  239.   rw_unlock(&hash->mutex);
  240.   DBUG_VOID_RETURN;
  241. }
  242. /*****************************************************************************
  243.   Functions to handle the key cache objects
  244. *****************************************************************************/
  245. /* Variable to store all key cache objects */
  246. static SAFE_HASH key_cache_hash;
  247. my_bool multi_keycache_init(void)
  248. {
  249.   return safe_hash_init(&key_cache_hash, 16, (byte*) dflt_key_cache);
  250. }
  251. void multi_keycache_free(void)
  252. {
  253.   safe_hash_free(&key_cache_hash);
  254. }
  255. /*
  256.   Get a key cache to be used for a specific table.
  257.   SYNOPSIS
  258.     multi_key_cache_search()
  259.     key key to find (usually table path)
  260.     uint length Length of key.
  261.   NOTES
  262.     This function is coded in such a way that we will return the
  263.     default key cache even if one never called multi_keycache_init.
  264.     This will ensure that it works with old MyISAM clients.
  265.   RETURN
  266.     key cache to use
  267. */
  268. KEY_CACHE *multi_key_cache_search(byte *key, uint length)
  269. {
  270.   if (!key_cache_hash.hash.records)
  271.     return dflt_key_cache;
  272.   return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
  273. }
  274. /*
  275.   Assosiate a key cache with a key
  276.   SYONOPSIS
  277.     multi_key_cache_set()
  278.     key key (path to table etc..)
  279.     length Length of key
  280.     key_cache cache to assococite with the table
  281.   NOTES
  282.     This can be used both to insert a new entry and change an existing
  283.     entry
  284. */
  285. my_bool multi_key_cache_set(const byte *key, uint length,
  286.     KEY_CACHE *key_cache)
  287. {
  288.   return safe_hash_set(&key_cache_hash, key, length, (byte*) key_cache);
  289. }
  290. void multi_key_cache_change(KEY_CACHE *old_data,
  291.     KEY_CACHE *new_data)
  292. {
  293.   safe_hash_change(&key_cache_hash, (byte*) old_data, (byte*) new_data);
  294. }