2006-08-10 19:19:47 +02:00
|
|
|
/* Copyright (C) 2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
/*
|
|
|
|
extensible hash
|
|
|
|
|
|
|
|
TODO
|
|
|
|
try to get rid of dummy nodes ?
|
2006-10-13 11:37:27 +02:00
|
|
|
for non-unique hash, count only _distinct_ values
|
2006-10-18 17:24:07 +02:00
|
|
|
(but how to do it in lf_hash_delete ?)
|
2006-08-10 19:19:47 +02:00
|
|
|
*/
|
|
|
|
#include <my_global.h>
|
2006-11-16 15:40:08 +01:00
|
|
|
#include <m_string.h>
|
2006-08-10 19:19:47 +02:00
|
|
|
#include <my_sys.h>
|
|
|
|
#include <my_bit.h>
|
|
|
|
#include <lf.h>
|
|
|
|
|
2006-12-04 15:31:04 +01:00
|
|
|
LF_REQUIRE_PINS(3);
|
2006-08-10 19:19:47 +02:00
|
|
|
|
2006-10-27 17:09:31 +02:00
|
|
|
/* An element of the list */
|
2006-08-10 19:19:47 +02:00
|
|
|
typedef struct {
|
2006-10-27 17:09:31 +02:00
|
|
|
intptr volatile link; /* a pointer to the next element in a listand a flag */
|
|
|
|
uint32 hashnr; /* reversed hash number, for sorting */
|
2006-11-16 15:40:08 +01:00
|
|
|
const byte *key;
|
2006-08-10 19:19:47 +02:00
|
|
|
uint keylen;
|
|
|
|
} LF_SLIST;
|
|
|
|
|
2006-10-27 17:09:31 +02:00
|
|
|
/*
|
|
|
|
a structure to pass the context (pointers two the three successive elements
|
|
|
|
in a list) from lfind to linsert/ldelete
|
|
|
|
*/
|
2006-08-10 19:19:47 +02:00
|
|
|
typedef struct {
|
|
|
|
intptr volatile *prev;
|
|
|
|
LF_SLIST *curr, *next;
|
|
|
|
} CURSOR;
|
|
|
|
|
2006-10-27 17:09:31 +02:00
|
|
|
/*
|
|
|
|
the last bit in LF_SLIST::link is a "deleted" flag.
|
|
|
|
the helper macros below convert it to a pure pointer or a pure flag
|
|
|
|
*/
|
2006-08-10 19:19:47 +02:00
|
|
|
#define PTR(V) (LF_SLIST *)((V) & (~(intptr)1))
|
|
|
|
#define DELETED(V) ((V) & 1)
|
|
|
|
|
|
|
|
/*
|
2006-10-27 17:09:31 +02:00
|
|
|
DESCRIPTION
|
|
|
|
Search for hashnr/key/keylen in the list starting from 'head' and
|
|
|
|
position the cursor. The list is ORDER BY hashnr, key
|
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
RETURN
|
|
|
|
0 - not found
|
|
|
|
1 - found
|
|
|
|
|
|
|
|
NOTE
|
|
|
|
cursor is positioned in either case
|
|
|
|
pins[0..2] are used, they are NOT removed on return
|
|
|
|
*/
|
2006-10-27 17:09:31 +02:00
|
|
|
static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
|
2006-11-16 15:40:08 +01:00
|
|
|
const byte *key, uint keylen, CURSOR *cursor, LF_PINS *pins)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
|
|
|
uint32 cur_hashnr;
|
2006-11-16 15:40:08 +01:00
|
|
|
const byte *cur_key;
|
2006-08-10 19:19:47 +02:00
|
|
|
uint cur_keylen;
|
|
|
|
intptr link;
|
|
|
|
|
|
|
|
retry:
|
2006-11-16 15:40:08 +01:00
|
|
|
cursor->prev= (intptr *)head;
|
2006-08-10 19:19:47 +02:00
|
|
|
do {
|
2006-11-16 15:40:08 +01:00
|
|
|
cursor->curr= PTR(*cursor->prev);
|
|
|
|
_lf_pin(pins, 1, cursor->curr);
|
2006-08-10 19:19:47 +02:00
|
|
|
} while(*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (!cursor->curr)
|
|
|
|
return 0;
|
2006-11-27 22:09:06 +01:00
|
|
|
do {
|
|
|
|
#warning XXX or goto retry ?
|
2006-11-16 15:40:08 +01:00
|
|
|
link= cursor->curr->link;
|
|
|
|
cursor->next= PTR(link);
|
2006-08-10 19:19:47 +02:00
|
|
|
_lf_pin(pins, 0, cursor->next);
|
|
|
|
} while(link != cursor->curr->link && LF_BACKOFF);
|
2006-11-16 15:40:08 +01:00
|
|
|
cur_hashnr= cursor->curr->hashnr;
|
|
|
|
cur_key= cursor->curr->key;
|
|
|
|
cur_keylen= cursor->curr->keylen;
|
2006-08-10 19:19:47 +02:00
|
|
|
if (*cursor->prev != (intptr)cursor->curr)
|
|
|
|
{
|
2006-12-07 15:23:50 +01:00
|
|
|
(void)LF_BACKOFF;
|
2006-08-10 19:19:47 +02:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
if (!DELETED(link))
|
|
|
|
{
|
|
|
|
if (cur_hashnr >= hashnr)
|
|
|
|
{
|
2006-11-16 15:40:08 +01:00
|
|
|
int r= 1;
|
2006-10-27 17:09:31 +02:00
|
|
|
if (cur_hashnr > hashnr ||
|
2006-11-16 15:40:08 +01:00
|
|
|
(r= my_strnncoll(cs, cur_key, cur_keylen, key, keylen)) >= 0)
|
2006-08-10 19:19:47 +02:00
|
|
|
return !r;
|
|
|
|
}
|
2006-11-16 15:40:08 +01:00
|
|
|
cursor->prev= &(cursor->curr->link);
|
2006-08-10 19:19:47 +02:00
|
|
|
_lf_pin(pins, 2, cursor->curr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (my_atomic_casptr((void **)cursor->prev,
|
|
|
|
(void **)&cursor->curr, cursor->next))
|
|
|
|
_lf_alloc_free(pins, cursor->curr);
|
|
|
|
else
|
|
|
|
{
|
2006-12-07 15:23:50 +01:00
|
|
|
(void)LF_BACKOFF;
|
2006-08-10 19:19:47 +02:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
2006-11-16 15:40:08 +01:00
|
|
|
cursor->curr= cursor->next;
|
2006-08-10 19:19:47 +02:00
|
|
|
_lf_pin(pins, 1, cursor->curr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-27 17:09:31 +02:00
|
|
|
DESCRIPTION
|
|
|
|
insert a 'node' in the list that starts from 'head' in the correct
|
|
|
|
position (as found by lfind)
|
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
RETURN
|
|
|
|
0 - inserted
|
2006-10-27 17:09:31 +02:00
|
|
|
not 0 - a pointer to a duplicate (not pinned and thus unusable)
|
2006-08-10 19:19:47 +02:00
|
|
|
|
|
|
|
NOTE
|
|
|
|
it uses pins[0..2], on return all pins are removed.
|
|
|
|
*/
|
2006-10-27 17:09:31 +02:00
|
|
|
static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
|
|
|
|
LF_SLIST *node, LF_PINS *pins, uint flags)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
|
|
|
CURSOR cursor;
|
2006-11-16 15:40:08 +01:00
|
|
|
int res= -1;
|
2006-08-10 19:19:47 +02:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2006-10-27 17:09:31 +02:00
|
|
|
if (lfind(head, cs, node->hashnr, node->key, node->keylen,
|
2006-08-10 19:19:47 +02:00
|
|
|
&cursor, pins) &&
|
|
|
|
(flags & LF_HASH_UNIQUE))
|
2006-11-16 15:40:08 +01:00
|
|
|
res= 0; /* duplicate found */
|
2006-08-10 19:19:47 +02:00
|
|
|
else
|
|
|
|
{
|
2006-11-16 15:40:08 +01:00
|
|
|
node->link= (intptr)cursor.curr;
|
2006-08-10 19:19:47 +02:00
|
|
|
assert(node->link != (intptr)node);
|
|
|
|
assert(cursor.prev != &node->link);
|
|
|
|
if (my_atomic_casptr((void **)cursor.prev, (void **)&cursor.curr, node))
|
2006-11-16 15:40:08 +01:00
|
|
|
res= 1; /* inserted ok */
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
|
|
|
} while (res == -1);
|
|
|
|
_lf_unpin(pins, 0);
|
|
|
|
_lf_unpin(pins, 1);
|
|
|
|
_lf_unpin(pins, 2);
|
|
|
|
return res ? 0 : cursor.curr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-27 17:09:31 +02:00
|
|
|
DESCRIPTION
|
|
|
|
deletes a node as identified by hashnr/keey/keylen from the list
|
|
|
|
that starts from 'head'
|
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
RETURN
|
|
|
|
0 - ok
|
|
|
|
1 - not found
|
2006-10-27 17:09:31 +02:00
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
NOTE
|
|
|
|
it uses pins[0..2], on return all pins are removed.
|
|
|
|
*/
|
2006-10-27 17:09:31 +02:00
|
|
|
static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
|
2006-11-16 15:40:08 +01:00
|
|
|
const byte *key, uint keylen, LF_PINS *pins)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
|
|
|
CURSOR cursor;
|
2006-11-16 15:40:08 +01:00
|
|
|
int res= -1;
|
2006-08-10 19:19:47 +02:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2006-10-27 17:09:31 +02:00
|
|
|
if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins))
|
2006-08-10 19:19:47 +02:00
|
|
|
res= 1;
|
|
|
|
else
|
|
|
|
if (my_atomic_casptr((void **)&(cursor.curr->link),
|
|
|
|
(void **)&cursor.next, 1+(char *)cursor.next))
|
|
|
|
{
|
|
|
|
if (my_atomic_casptr((void **)cursor.prev,
|
|
|
|
(void **)&cursor.curr, cursor.next))
|
|
|
|
_lf_alloc_free(pins, cursor.curr);
|
|
|
|
else
|
2006-10-27 17:09:31 +02:00
|
|
|
lfind(head, cs, hashnr, key, keylen, &cursor, pins);
|
2006-08-10 19:19:47 +02:00
|
|
|
res= 0;
|
|
|
|
}
|
|
|
|
} while (res == -1);
|
|
|
|
_lf_unpin(pins, 0);
|
|
|
|
_lf_unpin(pins, 1);
|
|
|
|
_lf_unpin(pins, 2);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-27 17:09:31 +02:00
|
|
|
DESCRIPTION
|
|
|
|
searches for a node as identified by hashnr/keey/keylen in the list
|
|
|
|
that starts from 'head'
|
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
RETURN
|
|
|
|
0 - not found
|
|
|
|
node - found
|
2006-10-27 17:09:31 +02:00
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
NOTE
|
|
|
|
it uses pins[0..2], on return the pin[2] keeps the node found
|
|
|
|
all other pins are removed.
|
|
|
|
*/
|
2006-10-27 17:09:31 +02:00
|
|
|
static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs,
|
2006-11-16 15:40:08 +01:00
|
|
|
uint32 hashnr, const byte *key, uint keylen,
|
2006-10-27 17:09:31 +02:00
|
|
|
LF_PINS *pins)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
|
|
|
CURSOR cursor;
|
2006-11-16 15:40:08 +01:00
|
|
|
int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins);
|
2006-08-10 19:19:47 +02:00
|
|
|
if (res) _lf_pin(pins, 2, cursor.curr);
|
|
|
|
_lf_unpin(pins, 0);
|
|
|
|
_lf_unpin(pins, 1);
|
|
|
|
return res ? cursor.curr : 0;
|
|
|
|
}
|
|
|
|
|
2006-11-16 15:40:08 +01:00
|
|
|
static inline const byte* hash_key(const LF_HASH *hash,
|
|
|
|
const byte *record, uint *length)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
|
|
|
if (hash->get_key)
|
2006-11-16 15:40:08 +01:00
|
|
|
return (*hash->get_key)(record, length, 0);
|
|
|
|
*length= hash->key_length;
|
2006-08-10 19:19:47 +02:00
|
|
|
return record + hash->key_offset;
|
|
|
|
}
|
|
|
|
|
2006-11-16 15:40:08 +01:00
|
|
|
static inline uint calc_hash(LF_HASH *hash, const byte *key, uint keylen)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
2006-11-16 15:40:08 +01:00
|
|
|
ulong nr1= 1, nr2= 4;
|
|
|
|
hash->charset->coll->hash_sort(hash->charset, key, keylen, &nr1, &nr2);
|
2006-08-10 19:19:47 +02:00
|
|
|
return nr1 & INT_MAX32;
|
|
|
|
}
|
|
|
|
|
2006-10-13 11:37:27 +02:00
|
|
|
#define MAX_LOAD 1.0
|
2006-08-10 19:19:47 +02:00
|
|
|
static void initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *);
|
|
|
|
|
2006-10-27 17:09:31 +02:00
|
|
|
/*
|
|
|
|
Initializes lf_hash, the arguments are compatible with hash_init
|
|
|
|
*/
|
2006-08-10 19:19:47 +02:00
|
|
|
void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
|
|
|
|
uint key_offset, uint key_length, hash_get_key get_key,
|
|
|
|
CHARSET_INFO *charset)
|
|
|
|
{
|
2006-10-18 17:24:07 +02:00
|
|
|
lf_alloc_init(&hash->alloc, sizeof(LF_SLIST)+element_size,
|
|
|
|
offsetof(LF_SLIST, key));
|
2006-08-10 19:19:47 +02:00
|
|
|
lf_dynarray_init(&hash->array, sizeof(LF_SLIST **));
|
2006-11-16 15:40:08 +01:00
|
|
|
hash->size= 1;
|
|
|
|
hash->count= 0;
|
|
|
|
hash->element_size= element_size;
|
|
|
|
hash->flags= flags;
|
|
|
|
hash->charset= charset ? charset : &my_charset_bin;
|
|
|
|
hash->key_offset= key_offset;
|
|
|
|
hash->key_length= key_length;
|
|
|
|
hash->get_key= get_key;
|
2006-08-10 19:19:47 +02:00
|
|
|
DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length);
|
|
|
|
}
|
|
|
|
|
2006-08-17 15:20:58 +02:00
|
|
|
void lf_hash_destroy(LF_HASH *hash)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
2006-11-16 15:40:08 +01:00
|
|
|
LF_SLIST *el= *(LF_SLIST **)_lf_dynarray_lvalue(&hash->array, 0);
|
2006-08-10 19:19:47 +02:00
|
|
|
while (el)
|
|
|
|
{
|
2006-11-16 15:40:08 +01:00
|
|
|
intptr next= el->link;
|
2006-08-17 15:22:54 +02:00
|
|
|
if (el->hashnr & 1)
|
|
|
|
lf_alloc_real_free(&hash->alloc, el);
|
|
|
|
else
|
|
|
|
my_free((void *)el, MYF(0));
|
2006-11-16 15:40:08 +01:00
|
|
|
el= (LF_SLIST *)next;
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
2006-08-17 15:20:58 +02:00
|
|
|
lf_alloc_destroy(&hash->alloc);
|
|
|
|
lf_dynarray_destroy(&hash->array);
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-27 17:09:31 +02:00
|
|
|
DESCRIPTION
|
|
|
|
inserts a new element to a hash. it will have a _copy_ of
|
|
|
|
data, not a pointer to it.
|
|
|
|
|
2006-08-17 15:20:58 +02:00
|
|
|
RETURN
|
|
|
|
0 - inserted
|
|
|
|
1 - didn't (unique key conflict)
|
2006-10-27 17:09:31 +02:00
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
NOTE
|
2006-08-17 15:20:58 +02:00
|
|
|
see linsert() for pin usage notes
|
2006-08-10 19:19:47 +02:00
|
|
|
*/
|
|
|
|
int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
|
|
|
|
{
|
2006-11-16 15:40:08 +01:00
|
|
|
int csize, bucket, hashnr;
|
2006-08-10 19:19:47 +02:00
|
|
|
LF_SLIST *node, * volatile *el;
|
|
|
|
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwlock_by_pins(pins);
|
2006-11-16 15:40:08 +01:00
|
|
|
node= (LF_SLIST *)_lf_alloc_new(pins);
|
2006-08-10 19:19:47 +02:00
|
|
|
memcpy(node+1, data, hash->element_size);
|
2006-11-16 15:40:08 +01:00
|
|
|
node->key= hash_key(hash, (byte *)(node+1), &node->keylen);
|
2006-08-17 15:20:58 +02:00
|
|
|
hashnr= calc_hash(hash, node->key, node->keylen);
|
|
|
|
bucket= hashnr % hash->size;
|
2006-11-16 15:40:08 +01:00
|
|
|
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
2006-08-10 19:19:47 +02:00
|
|
|
if (*el == NULL)
|
|
|
|
initialize_bucket(hash, el, bucket, pins);
|
2006-11-16 15:40:08 +01:00
|
|
|
node->hashnr= my_reverse_bits(hashnr) | 1;
|
2006-10-27 17:09:31 +02:00
|
|
|
if (linsert(el, hash->charset, node, pins, hash->flags))
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
|
|
|
_lf_alloc_free(pins, node);
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwunlock_by_pins(pins);
|
2006-08-17 15:20:58 +02:00
|
|
|
return 1;
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
|
|
|
csize= hash->size;
|
|
|
|
if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD)
|
|
|
|
my_atomic_cas32(&hash->size, &csize, csize*2);
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwunlock_by_pins(pins);
|
2006-08-17 15:20:58 +02:00
|
|
|
return 0;
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-08-17 15:20:58 +02:00
|
|
|
RETURN
|
|
|
|
0 - deleted
|
|
|
|
1 - didn't (not found)
|
2006-08-10 19:19:47 +02:00
|
|
|
NOTE
|
2006-08-17 15:20:58 +02:00
|
|
|
see ldelete() for pin usage notes
|
2006-08-10 19:19:47 +02:00
|
|
|
*/
|
2006-08-17 15:20:58 +02:00
|
|
|
int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
|
|
|
LF_SLIST * volatile *el;
|
2006-11-16 15:40:08 +01:00
|
|
|
uint bucket, hashnr= calc_hash(hash, (byte *)key, keylen);
|
2006-08-10 19:19:47 +02:00
|
|
|
|
|
|
|
bucket= hashnr % hash->size;
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwlock_by_pins(pins);
|
2006-11-16 15:40:08 +01:00
|
|
|
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
2006-08-10 19:19:47 +02:00
|
|
|
if (*el == NULL)
|
|
|
|
initialize_bucket(hash, el, bucket, pins);
|
2006-10-27 17:09:31 +02:00
|
|
|
if (ldelete(el, hash->charset, my_reverse_bits(hashnr) | 1,
|
2006-11-16 15:40:08 +01:00
|
|
|
(byte *)key, keylen, pins))
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwunlock_by_pins(pins);
|
2006-08-17 15:20:58 +02:00
|
|
|
return 1;
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
|
|
|
my_atomic_add32(&hash->count, -1);
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwunlock_by_pins(pins);
|
2006-08-17 15:20:58 +02:00
|
|
|
return 0;
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
NOTE
|
2006-08-17 15:20:58 +02:00
|
|
|
see lsearch() for pin usage notes
|
2006-08-10 19:19:47 +02:00
|
|
|
*/
|
2006-08-17 15:20:58 +02:00
|
|
|
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
2006-08-17 15:20:58 +02:00
|
|
|
LF_SLIST * volatile *el, *found;
|
2006-11-16 15:40:08 +01:00
|
|
|
uint bucket, hashnr= calc_hash(hash, (byte *)key, keylen);
|
2006-08-10 19:19:47 +02:00
|
|
|
|
|
|
|
bucket= hashnr % hash->size;
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwlock_by_pins(pins);
|
2006-11-16 15:40:08 +01:00
|
|
|
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
2006-08-10 19:19:47 +02:00
|
|
|
if (*el == NULL)
|
|
|
|
initialize_bucket(hash, el, bucket, pins);
|
2006-10-27 17:09:31 +02:00
|
|
|
found= lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1,
|
2006-11-16 15:40:08 +01:00
|
|
|
(byte *)key, keylen, pins);
|
2006-10-13 11:37:27 +02:00
|
|
|
lf_rwunlock_by_pins(pins);
|
|
|
|
return found ? found+1 : 0;
|
2006-08-10 19:19:47 +02:00
|
|
|
}
|
|
|
|
|
2006-11-16 15:40:08 +01:00
|
|
|
static char *dummy_key= "";
|
2006-08-17 15:22:54 +02:00
|
|
|
|
2006-08-10 19:19:47 +02:00
|
|
|
static void initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node,
|
|
|
|
uint bucket, LF_PINS *pins)
|
|
|
|
{
|
|
|
|
uint parent= my_clear_highest_bit(bucket);
|
2006-11-16 15:40:08 +01:00
|
|
|
LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME));
|
|
|
|
LF_SLIST **tmp= 0, *cur;
|
|
|
|
LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent);
|
2006-08-10 19:19:47 +02:00
|
|
|
if (*el == NULL && bucket)
|
|
|
|
initialize_bucket(hash, el, parent, pins);
|
2006-11-16 15:40:08 +01:00
|
|
|
dummy->hashnr= my_reverse_bits(bucket);
|
|
|
|
dummy->key= dummy_key;
|
|
|
|
dummy->keylen= 0;
|
2006-10-27 17:09:31 +02:00
|
|
|
if ((cur= linsert(el, hash->charset, dummy, pins, 0)))
|
2006-08-10 19:19:47 +02:00
|
|
|
{
|
2006-10-13 11:37:27 +02:00
|
|
|
my_free((void *)dummy, MYF(0));
|
2006-08-10 19:19:47 +02:00
|
|
|
dummy= cur;
|
|
|
|
}
|
|
|
|
my_atomic_casptr((void **)node, (void **)&tmp, dummy);
|
|
|
|
}
|
|
|
|
|