mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	 840fe316d4
			
		
	
	
	840fe316d4
	
	
	
		
			
			Partial commit of the greater MDEV-34348 scope. MDEV-34348: MariaDB is violating clang-16 -Wcast-function-type-strict Change the type of my_hash_get_key to: 1) Return const 2) Change the context parameter to be const void* Also fix casting in hash adjacent areas. Reviewed By: ============ Marko Mäkelä <marko.makela@mariadb.com>
		
			
				
	
	
		
			301 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			301 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (C) 2003-2007 MySQL AB
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation; either version 2 of the License, or
 | |
|    (at your option) any later version.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
 | |
| 
 | |
| /*
 | |
|   Handling of multiple key caches
 | |
| 
 | |
|   The idea is to have a thread safe hash on the table name,
 | |
|   with a default key cache value that is returned if the table name is not in
 | |
|   the cache.
 | |
| */
 | |
| 
 | |
| #include "mysys_priv.h"
 | |
| #include <m_string.h>
 | |
| #include "my_safehash.h"
 | |
| 
 | |
| /*****************************************************************************
 | |
|   General functions to handle SAFE_HASH objects.
 | |
| 
 | |
|   A SAFE_HASH object is used to store the hash, the mutex and default value
 | |
|   needed by the rest of the key cache code.
 | |
|   This is a separate struct to make it easy to later reuse the code for other
 | |
|   purposes
 | |
| 
 | |
|   All entries are linked in a list to allow us to traverse all elements
 | |
|   and delete selected ones. (HASH doesn't allow any easy ways to do this).
 | |
| *****************************************************************************/
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Free a SAFE_HASH_ENTRY
 | |
| 
 | |
|   SYNOPSIS
 | |
|     safe_hash_entry_free()
 | |
|     entry                The entry which should be freed
 | |
| 
 | |
|   NOTE
 | |
|     This function is called by the hash object on delete
 | |
| */
 | |
| 
 | |
| static void safe_hash_entry_free(void *entry_)
 | |
| {
 | |
|   SAFE_HASH_ENTRY *entry= entry_;
 | |
|   DBUG_ENTER("safe_hash_entry_free");
 | |
|   my_free(entry);
 | |
|   DBUG_VOID_RETURN;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Get key and length for a SAFE_HASH_ENTRY
 | |
| 
 | |
|   SYNOPSIS
 | |
|     safe_hash_entry_get()
 | |
|     entry                The entry for which the key should be returned
 | |
|     length               Length of the key
 | |
| 
 | |
|   RETURN
 | |
|     #  reference on the key
 | |
| */
 | |
| 
 | |
| static const uchar *safe_hash_entry_get(const void *entry_, size_t *length,
 | |
|                                         my_bool not_used
 | |
|                                         __attribute__((unused)))
 | |
| {
 | |
|   const SAFE_HASH_ENTRY *entry= entry_;
 | |
|   *length= entry->length;
 | |
|   return entry->key;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Init a SAFE_HASH object
 | |
| 
 | |
|   SYNOPSIS
 | |
|     safe_hash_init()
 | |
|     hash		safe_hash handler
 | |
|     elements		Expected max number of elements
 | |
|     default_value	default value
 | |
| 
 | |
|   NOTES
 | |
|     In case of error we set hash->default_value to 0 to allow one to call
 | |
|     safe_hash_free on an object that couldn't be initialized.
 | |
| 
 | |
|   RETURN
 | |
|     0  OK
 | |
|     1  error
 | |
| */
 | |
| 
 | |
| my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
 | |
|                        uchar *default_value)
 | |
| {
 | |
|   DBUG_ENTER("safe_hash_init");
 | |
|   if (my_hash_init(key_memory_SAFE_HASH_ENTRY, &hash->hash, &my_charset_bin,
 | |
|                    elements, 0, 0, safe_hash_entry_get, safe_hash_entry_free,
 | |
|                    0))
 | |
|   {
 | |
|     hash->default_value= 0;
 | |
|     DBUG_RETURN(1);
 | |
|   }
 | |
|   mysql_rwlock_init(key_SAFEHASH_mutex, &hash->mutex);
 | |
|   hash->default_value= default_value;
 | |
|   hash->root= 0;
 | |
|   DBUG_RETURN(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Free a SAFE_HASH object
 | |
| 
 | |
|   SYNOPSIS
 | |
|     safe_hash_free()
 | |
|     hash                 Hash handle
 | |
| 
 | |
|   NOTES
 | |
|     This is safe to call on any object that has been sent to safe_hash_init()
 | |
| */
 | |
| 
 | |
| void safe_hash_free(SAFE_HASH *hash)
 | |
| {
 | |
|   /*
 | |
|     Test if safe_hash_init succeeded. This will also guard us against multiple
 | |
|     free calls.
 | |
|   */
 | |
|   if (hash->default_value)
 | |
|   {
 | |
|     my_hash_free(&hash->hash);
 | |
|     mysql_rwlock_destroy(&hash->mutex);
 | |
|     hash->default_value=0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Return the value stored for a key or default value if no key
 | |
| 
 | |
|   SYNOPSIS
 | |
|     safe_hash_search()
 | |
|     hash                 Hash handle
 | |
|     key                  key (path to table etc..)
 | |
|     length               Length of key
 | |
|     def                  Default value of data
 | |
| 
 | |
|   RETURN
 | |
|     #  data associated with the key of default value if data was not found
 | |
| */
 | |
| 
 | |
| uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length,
 | |
|                         uchar *def)
 | |
| {
 | |
|   uchar *result;
 | |
|   DBUG_ENTER("safe_hash_search");
 | |
|   mysql_rwlock_rdlock(&hash->mutex);
 | |
|   result= my_hash_search(&hash->hash, key, length);
 | |
|   mysql_rwlock_unlock(&hash->mutex);
 | |
|   if (!result)
 | |
|     result= def;
 | |
|   else
 | |
|     result= ((SAFE_HASH_ENTRY*) result)->data;
 | |
|   DBUG_PRINT("exit",("data: %p", result));
 | |
|   DBUG_RETURN(result);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Associate a key with some data
 | |
| 
 | |
|   SYNOPSIS
 | |
|     safe_hash_set()
 | |
|     hash                 Hash handle
 | |
|     key                  key (path to table etc..)
 | |
|     length               Length of key
 | |
|     data                 data to to associate with the data
 | |
| 
 | |
|   NOTES
 | |
|     This can be used both to insert a new entry and change an existing
 | |
|     entry.
 | |
|     If one associates a key with the default key cache, the key is deleted
 | |
| 
 | |
|   RETURN
 | |
|     0  OK
 | |
|     1  error (Can only be EOM). In this case my_message() is called.
 | |
| */
 | |
| 
 | |
| my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
 | |
|                       uchar *data)
 | |
| {
 | |
|   SAFE_HASH_ENTRY *entry;
 | |
|   my_bool error= 0;
 | |
|   DBUG_ENTER("safe_hash_set");
 | |
|   DBUG_PRINT("enter",("key: %.*s  data: %p", length, key, data));
 | |
| 
 | |
|   mysql_rwlock_wrlock(&hash->mutex);
 | |
|   entry= (SAFE_HASH_ENTRY*) my_hash_search(&hash->hash, key, length);
 | |
| 
 | |
|   if (data == hash->default_value)
 | |
|   {
 | |
|     /*
 | |
|       The key is to be associated with the default entry. In this case
 | |
|       we can just delete the entry (if it existed) from the hash as a
 | |
|       search will return the default entry
 | |
|     */
 | |
|     if (!entry)          /* nothing to do */
 | |
|       goto end;
 | |
|     /* unlink entry from list */
 | |
|     if ((*entry->prev= entry->next))
 | |
|       entry->next->prev= entry->prev;
 | |
|     my_hash_delete(&hash->hash, (uchar*) entry);
 | |
|     goto end;
 | |
|   }
 | |
|   if (entry)
 | |
|   {
 | |
|     /* Entry existed;  Just change the pointer to point at the new data */
 | |
|     entry->data= data;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(key_memory_SAFE_HASH_ENTRY,
 | |
|                                                sizeof(*entry) + length,
 | |
|                                                MYF(MY_WME))))
 | |
|     {
 | |
|       error= 1;
 | |
|       goto end;
 | |
|     }
 | |
|     entry->key= (uchar*) (entry +1);
 | |
|     memcpy((char*) entry->key, (char*) key, length);
 | |
|     entry->length= length;
 | |
|     entry->data= data;
 | |
|     /* Link entry to list */
 | |
|     if ((entry->next= hash->root))
 | |
|       entry->next->prev= &entry->next;
 | |
|     entry->prev= &hash->root;
 | |
|     hash->root= entry;
 | |
|     if (my_hash_insert(&hash->hash, (uchar*) entry))
 | |
|     {
 | |
|       /* This can only happen if hash got out of memory */
 | |
|       my_free(entry);
 | |
|       error= 1;
 | |
|       goto end;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| end:
 | |
|   mysql_rwlock_unlock(&hash->mutex);
 | |
|   DBUG_RETURN(error);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Change all entries with one data value to another data value
 | |
| 
 | |
|   SYNOPSIS
 | |
|     safe_hash_change()
 | |
|     hash                 Hash handle
 | |
|     old_data             Old data
 | |
|     new_data             Change all 'old_data' to this
 | |
| 
 | |
|   NOTES
 | |
|     We use the linked list to traverse all elements in the hash as
 | |
|     this allows us to delete elements in the case where 'new_data' is the
 | |
|     default value.
 | |
| */
 | |
| 
 | |
| void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
 | |
| {
 | |
|   SAFE_HASH_ENTRY *entry, *next;
 | |
|   DBUG_ENTER("safe_hash_change");
 | |
| 
 | |
|   mysql_rwlock_wrlock(&hash->mutex);
 | |
| 
 | |
|   for (entry= hash->root ; entry ; entry= next)
 | |
|   {
 | |
|     next= entry->next;
 | |
|     if (entry->data == old_data)
 | |
|     {
 | |
|       if (new_data == hash->default_value)
 | |
|       {
 | |
|         if ((*entry->prev= entry->next))
 | |
|           entry->next->prev= entry->prev;
 | |
|         my_hash_delete(&hash->hash, (uchar*) entry);
 | |
|       }
 | |
|       else
 | |
|         entry->data= new_data;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   mysql_rwlock_unlock(&hash->mutex);
 | |
|   DBUG_VOID_RETURN;
 | |
| }
 |