mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	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;
 | 
						|
}
 |