diff options
Diffstat (limited to 'mysys/hash.c')
-rw-r--r-- | mysys/hash.c | 62 |
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) |