31
31
typedef struct st_hash_info {
32
uint32_t next; /* index to next key */
33
unsigned char *data; /* data for current entry */
32
uint next; /* index to next key */
33
uchar *data; /* data for current entry */
36
static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength);
37
static void movelink(HASH_LINK *array,uint32_t pos,uint32_t next_link,uint32_t newlink);
38
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
36
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
37
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
38
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
41
static uint32_t calc_hash(const HASH *hash, const unsigned char *key, size_t length)
41
static uint calc_hash(const HASH *hash, const uchar *key, size_t length)
43
uint32_t nr1=1, nr2=4;
44
hash->charset->coll->hash_sort(hash->charset,(const unsigned char*) key,length,&nr1,&nr2);
44
hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2);
49
_hash_init(HASH *hash,uint32_t growth_size, const CHARSET_INFO * const charset,
50
uint32_t size, size_t key_offset, size_t key_length,
49
_hash_init(HASH *hash,uint growth_size, CHARSET_INFO *charset,
50
ulong size, size_t key_offset, size_t key_length,
51
51
hash_get_key get_key,
52
void (*free_element)(void*),uint32_t flags CALLER_INFO_PROTO)
52
void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
54
DBUG_ENTER("hash_init");
55
DBUG_PRINT("enter",("hash: 0x%lx size: %u", (long) hash, (uint) size));
55
58
if (my_init_dynamic_array_ci(&hash->array, sizeof(HASH_LINK), size,
58
61
hash->free=0; /* Allow call to hash_free */
61
64
hash->key_offset=key_offset;
62
65
hash->key_length=key_length;
123
129
void my_hash_reset(HASH *hash)
131
DBUG_ENTER("my_hash_reset");
132
DBUG_PRINT("enter",("hash: 0x%lxd", (long) hash));
125
134
hash_free_elements(hash);
126
135
reset_dynamic(&hash->array);
127
136
/* Set row pointers so that the hash can be reused at once */
128
137
hash->blength= 1;
132
141
/* some helper functions */
135
This function is char* instead of unsigned char* as HPUX11 compiler can't
144
This function is char* instead of uchar* as HPUX11 compiler can't
136
145
handle inline functions that are not defined as native types
139
148
static inline char*
140
hash_key(const HASH *hash, const unsigned char *record, size_t *length,
149
hash_key(const HASH *hash, const uchar *record, size_t *length,
143
152
if (hash->get_key)
144
153
return (char*) (*hash->get_key)(record,length,first);
149
158
/* Calculate pos according to keys */
151
static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength)
160
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
153
162
if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
154
163
return (hashnr & ((buffmax >> 1) -1));
157
static uint32_t hash_rec_mask(const HASH *hash, HASH_LINK *pos,
158
uint32_t buffmax, uint32_t maxlength)
166
static uint hash_rec_mask(const HASH *hash, HASH_LINK *pos,
167
uint buffmax, uint maxlength)
161
unsigned char *key= (unsigned char*) hash_key(hash,pos->data,&length,0);
170
uchar *key= (uchar*) hash_key(hash,pos->data,&length,0);
162
171
return hash_mask(calc_hash(hash,key,length),buffmax,maxlength);
169
178
#if !defined(__USLC__) && !defined(__sgi)
172
unsigned int rec_hashnr(HASH *hash,const unsigned char *record)
181
unsigned int rec_hashnr(HASH *hash,const uchar *record)
175
unsigned char *key= (unsigned char*) hash_key(hash,record,&length,0);
184
uchar *key= (uchar*) hash_key(hash,record,&length,0);
176
185
return calc_hash(hash,key,length);
180
unsigned char* hash_search(const HASH *hash, const unsigned char *key, size_t length)
189
uchar* hash_search(const HASH *hash, const uchar *key, size_t length)
182
191
HASH_SEARCH_STATE state;
183
192
return hash_first(hash, key, length, &state);
190
199
Assigns the number of the found record to HASH_SEARCH_STATE state
193
unsigned char* hash_first(const HASH *hash, const unsigned char *key, size_t length,
202
uchar* hash_first(const HASH *hash, const uchar *key, size_t length,
194
203
HASH_SEARCH_STATE *current_record)
207
DBUG_ENTER("hash_first");
200
210
if (hash->records)
219
230
while ((idx=pos->next) != NO_RECORD);
221
232
*current_record= NO_RECORD;
225
236
/* Get next record with identical key */
226
237
/* Can only be called if previous calls was hash_search */
228
unsigned char* hash_next(const HASH *hash, const unsigned char *key, size_t length,
239
uchar* hash_next(const HASH *hash, const uchar *key, size_t length,
229
240
HASH_SEARCH_STATE *current_record)
234
245
if (*current_record != NO_RECORD)
282
293
!= 0 key of record != key
285
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
296
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
288
299
size_t rec_keylength;
289
unsigned char *rec_key= (unsigned char*) hash_key(hash,pos->data,&rec_keylength,1);
300
uchar *rec_key= (uchar*) hash_key(hash,pos->data,&rec_keylength,1);
290
301
return ((length && length != rec_keylength) ||
291
my_strnncoll(hash->charset, (const unsigned char*) rec_key, rec_keylength,
292
(const unsigned char*) key, rec_keylength));
302
my_strnncoll(hash->charset, (uchar*) rec_key, rec_keylength,
303
(uchar*) key, rec_keylength));
296
307
/* Write a hash-key to the hash-index */
298
bool my_hash_insert(HASH *info,const unsigned char *record)
309
my_bool my_hash_insert(HASH *info,const uchar *record)
302
uint32_t halfbuff,hash_nr,first_index;
303
unsigned char *ptr_to_rec=NULL,*ptr_to_rec2=NULL;
304
HASH_LINK *data,*empty,*gpos=NULL,*gpos2=NULL,*pos;
313
uint halfbuff,hash_nr,first_index;
314
uchar *ptr_to_rec,*ptr_to_rec2;
315
HASH_LINK *data,*empty,*gpos,*gpos2,*pos;
306
317
if (HASH_UNIQUE & info->flags)
308
unsigned char *key= (unsigned char*) hash_key(info, record, &idx, 1);
319
uchar *key= (uchar*) hash_key(info, record, &idx, 1);
309
320
if (hash_search(info, key, idx))
310
return(true); /* Duplicate entry */
321
return(TRUE); /* Duplicate entry */
314
325
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
315
return(true); /* No more memory */
326
return(TRUE); /* No more memory */
317
328
data=dynamic_element(&info->array,0,HASH_LINK*);
318
329
halfbuff= info->blength >> 1;
411
422
gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
414
pos->data=(unsigned char*) record;
425
pos->data=(uchar*) record;
415
426
pos->next=(uint) (empty - data);
419
pos->data=(unsigned char*) record;
430
pos->data=(uchar*) record;
420
431
pos->next=NO_RECORD;
421
432
movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
433
444
** if there is a free-function it's called for record if found
434
445
******************************************************************************/
436
bool hash_delete(HASH *hash,unsigned char *record)
447
my_bool hash_delete(HASH *hash,uchar *record)
438
uint32_t blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
449
uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
439
450
HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
451
DBUG_ENTER("hash_delete");
440
452
if (!hash->records)
443
455
blength=hash->blength;
444
456
data=dynamic_element(&hash->array,0,HASH_LINK*);
519
531
This is much more efficent than using a delete & insert.
522
bool hash_update(HASH *hash, unsigned char *record, unsigned char *old_key,
534
my_bool hash_update(HASH *hash, uchar *record, uchar *old_key,
523
535
size_t old_key_length)
525
uint32_t new_index,new_pos_index,blength,records,empty;
537
uint new_index,new_pos_index,blength,records,empty;
527
539
HASH_LINK org_link,*data,*previous,*pos;
540
DBUG_ENTER("hash_update");
529
542
if (HASH_UNIQUE & hash->flags)
531
544
HASH_SEARCH_STATE state;
532
unsigned char *found, *new_key= (unsigned char*) hash_key(hash, record, &idx, 1);
545
uchar *found, *new_key= (uchar*) hash_key(hash, record, &idx, 1);
533
546
if ((found= hash_first(hash, new_key, idx, &state)))
537
550
if (found != record)
538
return(1); /* Duplicate entry */
551
DBUG_RETURN(1); /* Duplicate entry */
540
553
while ((found= hash_next(hash, new_key, idx, &state)));
634
void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, unsigned char *new_row)
647
void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, uchar *new_row)
636
649
if (*current_record != NO_RECORD) /* Safety */
637
650
dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row;
656
my_bool hash_check(HASH *hash)
659
uint i,rec_link,found,max_links,seek,links,idx;
660
uint records,blength;
661
HASH_LINK *data,*hash_info;
663
records=hash->records; blength=hash->blength;
664
data=dynamic_element(&hash->array,0,HASH_LINK*);
667
for (i=found=max_links=seek=0 ; i < records ; i++)
669
if (hash_rec_mask(hash,data+i,blength,records) == i)
671
found++; seek++; links=1;
672
for (idx=data[i].next ;
673
idx != NO_RECORD && found < records + 1;
679
("Found pointer outside array to %d from link starting at %d",
685
if ((rec_link=hash_rec_mask(hash,hash_info,blength,records)) != i)
688
("Record in wrong link at %d: Start %d Record: 0x%lx Record-link %d",
689
idx, i, (long) hash_info->data, rec_link));
695
if (links > max_links) max_links=links;
698
if (found != records)
700
DBUG_PRINT("error",("Found %u of %u records", found, records));
705
("records: %u seeks: %d max links: %d hitrate: %.2f",
706
records,seek,max_links,(float) seek / (float) records));