summaryrefslogtreecommitdiff
path: root/mysys/hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/hash.c')
-rw-r--r--mysys/hash.c62
1 files changed, 36 insertions, 26 deletions
diff --git a/mysys/hash.c b/mysys/hash.c
index b93f6b666d6..3c17dcb991c 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2013, Monty Program 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
@@ -39,12 +40,12 @@ static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
size_t length);
-static my_hash_value_type calc_hash(const HASH *hash,
- const uchar *key, size_t length)
+my_hash_value_type my_hash_sort(CHARSET_INFO *cs, const uchar *key,
+ size_t length)
{
- ulong nr1=1, nr2=4;
- hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2);
- return (my_hash_value_type)nr1;
+ ulong nr1= 1, nr2= 4;
+ cs->coll->hash_sort(cs, (uchar*) key, length, &nr1, &nr2);
+ return (my_hash_value_type) nr1;
}
/**
@@ -59,7 +60,8 @@ static my_hash_value_type calc_hash(const HASH *hash,
as required during insertion.
@param[in,out] hash The hash that is initialized
- @param[in] charset The charater set information
+ @param[in[ growth_size size incrememnt for the underlying dynarray
+ @param[in] charset The character set information
@param[in] size The hash size
@param[in] key_offest The key offset for the hash
@param[in] key_length The length of the key used in
@@ -67,14 +69,16 @@ static my_hash_value_type calc_hash(const HASH *hash,
@param[in] get_key get the key for the hash
@param[in] free_element pointer to the function that
does cleanup
- @return inidicates success or failure of initialization
+ @param[in] flags flags set in the hash
+ @return indicates success or failure of initialization
@retval 0 success
@retval 1 failure
*/
my_bool
-_my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
+my_hash_init2(HASH *hash, uint growth_size, CHARSET_INFO *charset,
ulong size, size_t key_offset, size_t key_length,
my_hash_get_key get_key,
+ my_hash_function hash_function,
void (*free_element)(void*), uint flags)
{
my_bool res;
@@ -86,11 +90,13 @@ _my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
hash->key_length=key_length;
hash->blength=1;
hash->get_key=get_key;
+ hash->hash_function= hash_function ? hash_function : my_hash_sort;
hash->free=free_element;
hash->flags=flags;
hash->charset=charset;
- res= my_init_dynamic_array_ci(&hash->array,
- sizeof(HASH_LINK), size, growth_size);
+ res= init_dynamic_array2(&hash->array, sizeof(HASH_LINK), NULL, size,
+ growth_size, MYF((flags & HASH_THREAD_SPECIFIC ?
+ MY_THREAD_SPECIFIC : 0)));
DBUG_RETURN(res);
}
@@ -108,14 +114,19 @@ _my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
static inline void my_hash_free_elements(HASH *hash)
{
+ uint records= hash->records;
+ /*
+ Set records to 0 early to guard against anyone looking at the structure
+ during the free process
+ */
+ hash->records= 0;
if (hash->free)
{
HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
- HASH_LINK *end= data + hash->records;
+ HASH_LINK *end= data + records;
while (data < end)
(*hash->free)((data++)->data);
}
- hash->records=0;
}
@@ -195,7 +206,8 @@ static uint my_hash_rec_mask(const HASH *hash, HASH_LINK *pos,
{
size_t length;
uchar *key= (uchar*) my_hash_key(hash, pos->data, &length, 0);
- return my_hash_mask(calc_hash(hash, key, length), buffmax, maxlength);
+ return my_hash_mask(hash->hash_function(hash->charset, key, length), buffmax,
+ maxlength);
}
@@ -209,7 +221,7 @@ my_hash_value_type rec_hashnr(HASH *hash,const uchar *record)
{
size_t length;
uchar *key= (uchar*) my_hash_key(hash, record, &length, 0);
- return calc_hash(hash,key,length);
+ return hash->hash_function(hash->charset, key, length);
}
@@ -229,12 +241,6 @@ uchar* my_hash_search_using_hash_value(const HASH *hash,
key, length, &state);
}
-my_hash_value_type my_calc_hash(const HASH *hash,
- const uchar *key, size_t length)
-{
- return calc_hash(hash, key, length ? length : hash->key_length);
-}
-
/*
Search after a record based on a key
@@ -249,7 +255,8 @@ uchar* my_hash_first(const HASH *hash, const uchar *key, size_t length,
uchar *res;
if (my_hash_inited(hash))
res= my_hash_first_from_hash_value(hash,
- calc_hash(hash, key, length ? length : hash->key_length),
+ hash->hash_function(hash->charset, key,
+ length ? length : hash->key_length),
key, length, current_record);
else
res= 0;
@@ -516,6 +523,9 @@ my_bool my_hash_insert(HASH *info, const uchar *record)
The record with the same record ptr is removed.
If there is a free-function it's called if record was found.
+ hash->free() is guarantee to be called only after the row has been
+ deleted from the hash and the hash can be reused by other threads.
+
@return
@retval 0 ok
@retval 1 Record not found
@@ -608,7 +618,7 @@ exit:
/**
Update keys when record has changed.
- This is much more efficent than using a delete & insert.
+ This is much more efficient than using a delete & insert.
*/
my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key,
@@ -639,9 +649,9 @@ my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key,
/* Search after record with key */
- idx= my_hash_mask(calc_hash(hash, old_key, (old_key_length ?
- old_key_length :
- hash->key_length)),
+ idx= my_hash_mask(hash->hash_function(hash->charset, old_key,
+ (old_key_length ? old_key_length :
+ hash->key_length)),
blength, records);
new_index= my_hash_mask(rec_hashnr(hash, record), blength, records);
if (idx == new_index)