#include "mysys_priv.h"#include <m_string.h>#include <m_ctype.h>#include "hash.h"Include dependency graph for hash.c:

Go to the source code of this file.
Classes | |
| struct | st_hash_info |
Defines | |
| #define | NO_RECORD ((uint) -1) |
| #define | LOWFIND 1 |
| #define | LOWUSED 2 |
| #define | HIGHFIND 4 |
| #define | HIGHUSED 8 |
Typedefs | |
| typedef st_hash_info | HASH_LINK |
Functions | |
| static uint | hash_mask (uint hashnr, uint buffmax, uint maxlength) |
| static void | movelink (HASH_LINK *array, uint pos, uint next_link, uint newlink) |
| static int | hashcmp (const HASH *hash, HASH_LINK *pos, const byte *key, uint length) |
| static uint | calc_hash (const HASH *hash, const byte *key, uint length) |
| my_bool | _hash_init (HASH *hash, CHARSET_INFO *charset, uint size, uint key_offset, uint key_length, hash_get_key get_key, void(*free_element)(void *), uint flags CALLER_INFO_PROTO) |
| static void | hash_free_elements (HASH *hash) |
| void | hash_free (HASH *hash) |
| void | my_hash_reset (HASH *hash) |
| static char * | hash_key (const HASH *hash, const byte *record, uint *length, my_bool first) |
| static uint | hash_rec_mask (const HASH *hash, HASH_LINK *pos, uint buffmax, uint maxlength) |
| static unsigned int | rec_hashnr (HASH *hash, const byte *record) |
| gptr | hash_search (const HASH *hash, const byte *key, uint length) |
| gptr | hash_first (const HASH *hash, const byte *key, uint length, HASH_SEARCH_STATE *current_record) |
| gptr | hash_next (const HASH *hash, const byte *key, uint length, HASH_SEARCH_STATE *current_record) |
| my_bool | my_hash_insert (HASH *info, const byte *record) |
| my_bool | hash_delete (HASH *hash, byte *record) |
| my_bool | hash_update (HASH *hash, byte *record, byte *old_key, uint old_key_length) |
| byte * | hash_element (HASH *hash, uint idx) |
| void | hash_replace (HASH *hash, HASH_SEARCH_STATE *current_record, byte *new_row) |
| my_bool | hash_check (HASH *hash) |
| typedef struct st_hash_info HASH_LINK |
| my_bool _hash_init | ( | HASH * | hash, | |
| CHARSET_INFO * | charset, | |||
| uint | size, | |||
| uint | key_offset, | |||
| uint | key_length, | |||
| hash_get_key | get_key, | |||
| void(*)(void *) | free_element, | |||
| uint flags | CALLER_INFO_PROTO | |||
| ) |
Definition at line 50 of file hash.c.
References charset, DBUG_ENTER, DBUG_PRINT, DBUG_RETURN, flags, hash(), and my_init_dynamic_array_ci.
00054 { 00055 DBUG_ENTER("hash_init"); 00056 DBUG_PRINT("enter",("hash: 0x%lx size: %d",hash,size)); 00057 00058 hash->records=0; 00059 if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,0)) 00060 { 00061 hash->free=0; /* Allow call to hash_free */ 00062 DBUG_RETURN(1); 00063 } 00064 hash->key_offset=key_offset; 00065 hash->key_length=key_length; 00066 hash->blength=1; 00067 hash->get_key=get_key; 00068 hash->free=free_element; 00069 hash->flags=flags; 00070 hash->charset=charset; 00071 DBUG_RETURN(0); 00072 }
Here is the call graph for this function:

Definition at line 615 of file hash.c.
References data, DBUG_PRINT, dynamic_element, error, hash(), hash_rec_mask(), st_hash_link::next, NO_RECORD, and records.
00616 { 00617 int error; 00618 uint i,rec_link,found,max_links,seek,links,idx; 00619 uint records,blength; 00620 HASH_LINK *data,*hash_info; 00621 00622 records=hash->records; blength=hash->blength; 00623 data=dynamic_element(&hash->array,0,HASH_LINK*); 00624 error=0; 00625 00626 for (i=found=max_links=seek=0 ; i < records ; i++) 00627 { 00628 if (hash_rec_mask(hash,data+i,blength,records) == i) 00629 { 00630 found++; seek++; links=1; 00631 for (idx=data[i].next ; 00632 idx != NO_RECORD && found < records + 1; 00633 idx=hash_info->next) 00634 { 00635 if (idx >= records) 00636 { 00637 DBUG_PRINT("error", 00638 ("Found pointer outside array to %d from link starting at %d", 00639 idx,i)); 00640 error=1; 00641 } 00642 hash_info=data+idx; 00643 seek+= ++links; 00644 if ((rec_link=hash_rec_mask(hash,hash_info,blength,records)) != i) 00645 { 00646 DBUG_PRINT("error", 00647 ("Record in wrong link at %d: Start %d Record: 0x%lx Record-link %d", idx,i,hash_info->data,rec_link)); 00648 error=1; 00649 } 00650 else 00651 found++; 00652 } 00653 if (links > max_links) max_links=links; 00654 } 00655 } 00656 if (found != records) 00657 { 00658 DBUG_PRINT("error",("Found %ld of %ld records")); 00659 error=1; 00660 } 00661 if (records) 00662 DBUG_PRINT("info", 00663 ("records: %ld seeks: %d max links: %d hitrate: %.2f", 00664 records,seek,max_links,(float) seek / (float) records)); 00665 return error; 00666 }
Here is the call graph for this function:

Definition at line 442 of file hash.c.
References data, DBUG_ENTER, DBUG_RETURN, dynamic_element, empty, exit, hash(), hash_mask(), movelink(), st_hash_link::next, NO_RECORD, pop_dynamic(), pos(), rec_hashnr(), and VOID.
00443 { 00444 uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index; 00445 HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty; 00446 DBUG_ENTER("hash_delete"); 00447 if (!hash->records) 00448 DBUG_RETURN(1); 00449 00450 blength=hash->blength; 00451 data=dynamic_element(&hash->array,0,HASH_LINK*); 00452 /* Search after record with key */ 00453 pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records); 00454 gpos = 0; 00455 00456 while (pos->data != record) 00457 { 00458 gpos=pos; 00459 if (pos->next == NO_RECORD) 00460 DBUG_RETURN(1); /* Key not found */ 00461 pos=data+pos->next; 00462 } 00463 00464 if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1; 00465 lastpos=data+hash->records; 00466 00467 /* Remove link to record */ 00468 empty=pos; empty_index=(uint) (empty-data); 00469 if (gpos) 00470 gpos->next=pos->next; /* unlink current ptr */ 00471 else if (pos->next != NO_RECORD) 00472 { 00473 empty=data+(empty_index=pos->next); 00474 pos->data=empty->data; 00475 pos->next=empty->next; 00476 } 00477 00478 if (empty == lastpos) /* last key at wrong pos or no next link */ 00479 goto exit; 00480 00481 /* Move the last key (lastpos) */ 00482 lastpos_hashnr=rec_hashnr(hash,lastpos->data); 00483 /* pos is where lastpos should be */ 00484 pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records); 00485 if (pos == empty) /* Move to empty position. */ 00486 { 00487 empty[0]=lastpos[0]; 00488 goto exit; 00489 } 00490 pos_hashnr=rec_hashnr(hash,pos->data); 00491 /* pos3 is where the pos should be */ 00492 pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records); 00493 if (pos != pos3) 00494 { /* pos is on wrong posit */ 00495 empty[0]=pos[0]; /* Save it here */ 00496 pos[0]=lastpos[0]; /* This should be here */ 00497 movelink(data,(uint) (pos-data),(uint) (pos3-data),empty_index); 00498 goto exit; 00499 } 00500 pos2= hash_mask(lastpos_hashnr,blength,hash->records+1); 00501 if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1)) 00502 { /* Identical key-positions */ 00503 if (pos2 != hash->records) 00504 { 00505 empty[0]=lastpos[0]; 00506 movelink(data,(uint) (lastpos-data),(uint) (pos-data),empty_index); 00507 goto exit; 00508 } 00509 idx= (uint) (pos-data); /* Link pos->next after lastpos */ 00510 } 00511 else idx= NO_RECORD; /* Different positions merge */ 00512 00513 empty[0]=lastpos[0]; 00514 movelink(data,idx,empty_index,pos->next); 00515 pos->next=empty_index; 00516 00517 exit: 00518 VOID(pop_dynamic(&hash->array)); 00519 if (hash->free) 00520 (*hash->free)((byte*) record); 00521 DBUG_RETURN(0); 00522 }
Here is the call graph for this function:

Definition at line 593 of file hash.c.
References dynamic_element, hash(), and records.
00594 { 00595 if (idx < hash->records) 00596 return dynamic_element(&hash->array,idx,HASH_LINK*)->data; 00597 return 0; 00598 }
Here is the call graph for this function:

| gptr hash_first | ( | const HASH * | hash, | |
| const byte * | key, | |||
| uint | length, | |||
| HASH_SEARCH_STATE * | current_record | |||
| ) |
Definition at line 202 of file hash.c.
References calc_hash(), DBUG_ENTER, DBUG_PRINT, DBUG_RETURN, dynamic_element, flag, hash(), hash_mask(), hash_rec_mask(), hashcmp(), NO_RECORD, and pos().
00204 { 00205 HASH_LINK *pos; 00206 uint flag,idx; 00207 DBUG_ENTER("hash_first"); 00208 00209 flag=1; 00210 if (hash->records) 00211 { 00212 idx=hash_mask(calc_hash(hash,key,length ? length : hash->key_length), 00213 hash->blength,hash->records); 00214 do 00215 { 00216 pos= dynamic_element(&hash->array,idx,HASH_LINK*); 00217 if (!hashcmp(hash,pos,key,length)) 00218 { 00219 DBUG_PRINT("exit",("found key at %d",idx)); 00220 *current_record= idx; 00221 DBUG_RETURN (pos->data); 00222 } 00223 if (flag) 00224 { 00225 flag=0; /* Reset flag */ 00226 if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx) 00227 break; /* Wrong link */ 00228 } 00229 } 00230 while ((idx=pos->next) != NO_RECORD); 00231 } 00232 *current_record= NO_RECORD; 00233 DBUG_RETURN(0); 00234 }
Here is the call graph for this function:

| void hash_free | ( | HASH * | hash | ) |
Definition at line 109 of file hash.c.
References DBUG_ENTER, DBUG_PRINT, DBUG_VOID_RETURN, delete_dynamic(), hash(), and hash_free_elements().
00110 { 00111 DBUG_ENTER("hash_free"); 00112 DBUG_PRINT("enter",("hash: 0x%lx", hash)); 00113 00114 hash_free_elements(hash); 00115 hash->free= 0; 00116 delete_dynamic(&hash->array); 00117 DBUG_VOID_RETURN; 00118 }
Here is the call graph for this function:

| static void hash_free_elements | ( | HASH * | hash | ) | [inline, static] |
Definition at line 86 of file hash.c.
References data, dynamic_element, and hash().
00087 { 00088 if (hash->free) 00089 { 00090 HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*); 00091 HASH_LINK *end= data + hash->records; 00092 while (data < end) 00093 (*hash->free)((data++)->data); 00094 } 00095 hash->records=0; 00096 }
Here is the call graph for this function:

| gptr hash_next | ( | const HASH * | hash, | |
| const byte * | key, | |||
| uint | length, | |||
| HASH_SEARCH_STATE * | current_record | |||
| ) |
Definition at line 239 of file hash.c.
References data, dynamic_element, hash(), hashcmp(), NO_RECORD, and pos().
00241 { 00242 HASH_LINK *pos; 00243 uint idx; 00244 00245 if (*current_record != NO_RECORD) 00246 { 00247 HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*); 00248 for (idx=data[*current_record].next; idx != NO_RECORD ; idx=pos->next) 00249 { 00250 pos=data+idx; 00251 if (!hashcmp(hash,pos,key,length)) 00252 { 00253 *current_record= idx; 00254 return pos->data; 00255 } 00256 } 00257 *current_record= NO_RECORD; 00258 } 00259 return 0; 00260 }
Here is the call graph for this function:

| static uint hash_rec_mask | ( | const HASH * | hash, | |
| HASH_LINK * | pos, | |||
| uint | buffmax, | |||
| uint | maxlength | |||
| ) | [static] |
Definition at line 166 of file hash.c.
References calc_hash(), hash(), hash_key(), hash_mask(), key, and pos().
00168 { 00169 uint length; 00170 byte *key= (byte*) hash_key(hash,pos->data,&length,0); 00171 return hash_mask(calc_hash(hash,key,length),buffmax,maxlength); 00172 }
Here is the call graph for this function:

| void hash_replace | ( | HASH * | hash, | |
| HASH_SEARCH_STATE * | current_record, | |||
| byte * | new_row | |||
| ) |
Definition at line 606 of file hash.c.
References dynamic_element, hash(), and NO_RECORD.
00607 { 00608 if (*current_record != NO_RECORD) /* Safety */ 00609 dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row; 00610 }
Here is the call graph for this function:

Definition at line 189 of file hash.c.
References hash(), and hash_first().
00190 { 00191 HASH_SEARCH_STATE state; 00192 return hash_first(hash, key, length, &state); 00193 }
Here is the call graph for this function:

Definition at line 529 of file hash.c.
References calc_hash(), data, DBUG_ENTER, DBUG_RETURN, dynamic_element, empty, hash(), hash_mask(), NO_RECORD, pos(), rec_hashnr(), and records.
00530 { 00531 uint idx,new_index,new_pos_index,blength,records,empty; 00532 HASH_LINK org_link,*data,*previous,*pos; 00533 DBUG_ENTER("hash_update"); 00534 00535 data=dynamic_element(&hash->array,0,HASH_LINK*); 00536 blength=hash->blength; records=hash->records; 00537 00538 /* Search after record with key */ 00539 00540 idx=hash_mask(calc_hash(hash, old_key,(old_key_length ? 00541 old_key_length : 00542 hash->key_length)), 00543 blength,records); 00544 new_index=hash_mask(rec_hashnr(hash,record),blength,records); 00545 if (idx == new_index) 00546 DBUG_RETURN(0); /* Nothing to do (No record check) */ 00547 previous=0; 00548 for (;;) 00549 { 00550 00551 if ((pos= data+idx)->data == record) 00552 break; 00553 previous=pos; 00554 if ((idx=pos->next) == NO_RECORD) 00555 DBUG_RETURN(1); /* Not found in links */ 00556 } 00557 org_link= *pos; 00558 empty=idx; 00559 00560 /* Relink record from current chain */ 00561 00562 if (!previous) 00563 { 00564 if (pos->next != NO_RECORD) 00565 { 00566 empty=pos->next; 00567 *pos= data[pos->next]; 00568 } 00569 } 00570 else 00571 previous->next=pos->next; /* unlink pos */ 00572 00573 /* Move data to correct position */ 00574 pos=data+new_index; 00575 new_pos_index=hash_rec_mask(hash,pos,blength,records); 00576 if (new_index != new_pos_index) 00577 { /* Other record in wrong position */ 00578 data[empty] = *pos; 00579 movelink(data,new_index,new_pos_index,empty); 00580 org_link.next=NO_RECORD; 00581 data[new_index]= org_link; 00582 } 00583 else 00584 { /* Link in chain at right position */ 00585 org_link.next=data[new_index].next; 00586 data[empty]=org_link; 00587 data[new_index].next=empty; 00588 } 00589 DBUG_RETURN(0); 00590 }
Here is the call graph for this function:

Definition at line 296 of file hash.c.
References hash(), hash_key(), my_strnncoll, and pos().
00298 { 00299 uint rec_keylength; 00300 byte *rec_key= (byte*) hash_key(hash,pos->data,&rec_keylength,1); 00301 return ((length && length != rec_keylength) || 00302 my_strnncoll(hash->charset, (uchar*) rec_key, rec_keylength, 00303 (uchar*) key, rec_keylength)); 00304 }
Here is the call graph for this function:

Definition at line 309 of file hash.c.
References alloc_dynamic(), st_hash::array, st_hash::blength, data, dynamic_element, empty, flag, hash_mask(), hash_rec_mask(), HIGHFIND, HIGHUSED, LINT_INIT, LOWFIND, LOWUSED, movelink(), st_hash_link::next, NO_RECORD, pos(), rec_hashnr(), st_hash::records, and TRUE.
00310 { 00311 int flag; 00312 uint halfbuff,hash_nr,first_index,idx; 00313 byte *ptr_to_rec,*ptr_to_rec2; 00314 HASH_LINK *data,*empty,*gpos,*gpos2,*pos; 00315 00316 LINT_INIT(gpos); LINT_INIT(gpos2); 00317 LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2); 00318 00319 flag=0; 00320 if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array))) 00321 return(TRUE); /* No more memory */ 00322 00323 data=dynamic_element(&info->array,0,HASH_LINK*); 00324 halfbuff= info->blength >> 1; 00325 00326 idx=first_index=info->records-halfbuff; 00327 if (idx != info->records) /* If some records */ 00328 { 00329 do 00330 { 00331 pos=data+idx; 00332 hash_nr=rec_hashnr(info,pos->data); 00333 if (flag == 0) /* First loop; Check if ok */ 00334 if (hash_mask(hash_nr,info->blength,info->records) != first_index) 00335 break; 00336 if (!(hash_nr & halfbuff)) 00337 { /* Key will not move */ 00338 if (!(flag & LOWFIND)) 00339 { 00340 if (flag & HIGHFIND) 00341 { 00342 flag=LOWFIND | HIGHFIND; 00343 /* key shall be moved to the current empty position */ 00344 gpos=empty; 00345 ptr_to_rec=pos->data; 00346 empty=pos; /* This place is now free */ 00347 } 00348 else 00349 { 00350 flag=LOWFIND | LOWUSED; /* key isn't changed */ 00351 gpos=pos; 00352 ptr_to_rec=pos->data; 00353 } 00354 } 00355 else 00356 { 00357 if (!(flag & LOWUSED)) 00358 { 00359 /* Change link of previous LOW-key */ 00360 gpos->data=ptr_to_rec; 00361 gpos->next=(uint) (pos-data); 00362 flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED); 00363 } 00364 gpos=pos; 00365 ptr_to_rec=pos->data; 00366 } 00367 } 00368 else 00369 { /* key will be moved */ 00370 if (!(flag & HIGHFIND)) 00371 { 00372 flag= (flag & LOWFIND) | HIGHFIND; 00373 /* key shall be moved to the last (empty) position */ 00374 gpos2 = empty; empty=pos; 00375 ptr_to_rec2=pos->data; 00376 } 00377 else 00378 { 00379 if (!(flag & HIGHUSED)) 00380 { 00381 /* Change link of previous hash-key and save */ 00382 gpos2->data=ptr_to_rec2; 00383 gpos2->next=(uint) (pos-data); 00384 flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED); 00385 } 00386 gpos2=pos; 00387 ptr_to_rec2=pos->data; 00388 } 00389 } 00390 } 00391 while ((idx=pos->next) != NO_RECORD); 00392 00393 if ((flag & (LOWFIND | LOWUSED)) == LOWFIND) 00394 { 00395 gpos->data=ptr_to_rec; 00396 gpos->next=NO_RECORD; 00397 } 00398 if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND) 00399 { 00400 gpos2->data=ptr_to_rec2; 00401 gpos2->next=NO_RECORD; 00402 } 00403 } 00404 /* Check if we are at the empty position */ 00405 00406 idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1); 00407 pos=data+idx; 00408 if (pos == empty) 00409 { 00410 pos->data=(byte*) record; 00411 pos->next=NO_RECORD; 00412 } 00413 else 00414 { 00415 /* Check if more records in same hash-nr family */ 00416 empty[0]=pos[0]; 00417 gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1); 00418 if (pos == gpos) 00419 { 00420 pos->data=(byte*) record; 00421 pos->next=(uint) (empty - data); 00422 } 00423 else 00424 { 00425 pos->data=(byte*) record; 00426 pos->next=NO_RECORD; 00427 movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data)); 00428 } 00429 } 00430 if (++info->records == info->blength) 00431 info->blength+= info->blength; 00432 return(0); 00433 }
Here is the call graph for this function:

| void my_hash_reset | ( | HASH * | hash | ) |
Definition at line 129 of file hash.c.
References DBUG_ENTER, DBUG_PRINT, DBUG_VOID_RETURN, hash(), hash_free_elements(), and reset_dynamic.
00130 { 00131 DBUG_ENTER("my_hash_reset"); 00132 DBUG_PRINT("enter",("hash: 0x%lxd",hash)); 00133 00134 hash_free_elements(hash); 00135 reset_dynamic(&hash->array); 00136 /* Set row pointers so that the hash can be reused at once */ 00137 hash->blength= 1; 00138 DBUG_VOID_RETURN; 00139 }
Here is the call graph for this function:

1.4.7

