hp_hash.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:8k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16. /* The hash functions used for saveing keys */
  17. #include "heapdef.h"
  18. #include <m_ctype.h>
  19. /* Search after a record based on a key */
  20. /* Sets info->current_ptr to found record */
  21. /* next_flag:  Search=0, next=1, prev =2, same =3 */
  22. byte *_hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *key,
  23.  uint nextflag)
  24. {
  25.   reg1 HASH_INFO *pos,*prev_ptr;
  26.   int flag;
  27.   uint old_nextflag;
  28.   HP_SHARE *share=info->s;
  29.   DBUG_ENTER("_hp_search");
  30.   old_nextflag=nextflag;
  31.   flag=1;
  32.   prev_ptr=0;
  33.   if (share->records)
  34.   {
  35.     pos=hp_find_hash(&keyinfo->block,_hp_mask(_hp_hashnr(keyinfo,key),
  36.       share->blength,share->records));
  37.     do
  38.     {
  39.       if (!_hp_key_cmp(keyinfo,pos->ptr_to_rec,key))
  40.       {
  41. switch (nextflag) {
  42. case 0: /* Search after key */
  43.   DBUG_PRINT("exit",("found key at %d",pos->ptr_to_rec));
  44.   info->current_hash_ptr=pos;
  45.   DBUG_RETURN(info->current_ptr= pos->ptr_to_rec);
  46. case 1: /* Search next */
  47.   if (pos->ptr_to_rec == info->current_ptr)
  48.     nextflag=0;
  49.   break;
  50. case 2: /* Search previous */
  51.   if (pos->ptr_to_rec == info->current_ptr)
  52.   {
  53.     my_errno=HA_ERR_KEY_NOT_FOUND; /* If gpos == 0 */
  54.     info->current_hash_ptr=prev_ptr;
  55.     DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
  56.   }
  57.   prev_ptr=pos; /* Prev. record found */
  58.   break;
  59. case 3: /* Search same */
  60.   if (pos->ptr_to_rec == info->current_ptr)
  61.   {
  62.     info->current_hash_ptr=pos;
  63.     DBUG_RETURN(info->current_ptr);
  64.   }
  65. }
  66.       }
  67.       if (flag)
  68.       {
  69. flag=0; /* Reset flag */
  70. if (hp_find_hash(&keyinfo->block,
  71.  _hp_mask(_hp_rec_hashnr(keyinfo,pos->ptr_to_rec),
  72.   share->blength,share->records)) != pos)
  73.   break; /* Wrong link */
  74.       }
  75.     }
  76.     while ((pos=pos->next_key));
  77.   }
  78.   my_errno=HA_ERR_KEY_NOT_FOUND;
  79.   if (nextflag == 2 && ! info->current_ptr)
  80.   {
  81.     /* Do a previous from end */
  82.     info->current_hash_ptr=prev_ptr;
  83.     DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
  84.   }
  85.   if (old_nextflag && nextflag)
  86.     my_errno=HA_ERR_RECORD_CHANGED; /* Didn't find old record */
  87.   DBUG_PRINT("exit",("Error: %d",my_errno));
  88.   info->current_hash_ptr=0;  
  89.   DBUG_RETURN((info->current_ptr= 0));
  90. }
  91. /*
  92.   Search next after last read;  Assumes that the table hasn't changed
  93.   since last read !
  94. */
  95. byte *_hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *key,
  96.       HASH_INFO *pos)
  97. {
  98.   DBUG_ENTER("_hp_search_next");
  99.   while ((pos= pos->next_key))
  100.   {
  101.     if (!_hp_key_cmp(keyinfo,pos->ptr_to_rec,key))
  102.     {
  103.       info->current_hash_ptr=pos;
  104.       DBUG_RETURN (info->current_ptr= pos->ptr_to_rec);
  105.     }
  106.   }
  107.   my_errno=HA_ERR_KEY_NOT_FOUND;
  108.   DBUG_PRINT("exit",("Error: %d",my_errno));
  109.   info->current_hash_ptr=0;
  110.   DBUG_RETURN ((info->current_ptr= 0));
  111. }
  112. /* Calculate pos according to keys */
  113. ulong _hp_mask(ulong hashnr, ulong buffmax, ulong maxlength)
  114. {
  115.   if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
  116.   return (hashnr & ((buffmax >> 1) -1));
  117. }
  118. /* Change link from pos to new_link */
  119. void _hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink)
  120. {
  121.   HASH_INFO *old_link;
  122.   do
  123.   {
  124.     old_link=next_link;
  125.   }
  126.   while ((next_link=next_link->next_key) != pos);
  127.   old_link->next_key=newlink;
  128.   return;
  129. }
  130. #ifndef NEW_HASH_FUNCTION
  131. /* Calc hashvalue for a key */
  132. ulong _hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
  133. {
  134.   register ulong nr=1, nr2=4;
  135.   HP_KEYSEG *seg,*endseg;
  136.   for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
  137.   {
  138.     uchar *pos=(uchar*) key;
  139.     key+=seg->length;
  140.     if (seg->type == HA_KEYTYPE_TEXT)
  141.     {
  142.       for (; pos < (uchar*) key ; pos++)
  143.       {
  144. nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
  145. nr2+=3;
  146.       }
  147.     }
  148.     else
  149.     {
  150.       for (; pos < (uchar*) key ; pos++)
  151.       {
  152. nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
  153. nr2+=3;
  154.       }
  155.     }
  156.   }
  157.   return((ulong) nr);
  158. }
  159. /* Calc hashvalue for a key in a record */
  160. ulong _hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
  161. {
  162.   register ulong nr=1, nr2=4;
  163.   HP_KEYSEG *seg,*endseg;
  164.   for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
  165.   {
  166.     uchar *pos=(uchar*) rec+seg->start,*end=pos+seg->length;
  167.     if (seg->type == HA_KEYTYPE_TEXT)
  168.     {
  169.       for (; pos < end ; pos++)
  170.       {
  171. nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) my_sort_order[(uint) *pos]))+ (nr << 8);
  172. nr2+=3;
  173.       }
  174.     }
  175.     else
  176.     {
  177.       for (; pos < end ; pos++)
  178.       {
  179. nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
  180. nr2+=3;
  181.       }
  182.     }
  183.   }
  184.   return((ulong) nr);
  185. }
  186. #else
  187. /*
  188.  * Fowler/Noll/Vo hash
  189.  *
  190.  * The basis of the hash algorithm was taken from an idea sent by email to the
  191.  * IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
  192.  * Glenn Fowler (gsf@research.att.com).  Landon Curt Noll (chongo@toad.com)
  193.  * later improved on their algorithm.
  194.  *
  195.  * The magic is in the interesting relationship between the special prime
  196.  * 16777619 (2^24 + 403) and 2^32 and 2^8.
  197.  *
  198.  * This hash produces the fewest collisions of any function that we've seen so
  199.  * far, and works well on both numbers and strings.
  200.  */
  201. ulong _hp_hashnr(register HP_KEYDEF *keydef, register const byte *key)
  202. {
  203.   register ulong nr=0;
  204.   HP_KEYSEG *seg,*endseg;
  205.   for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
  206.   {
  207.     uchar *pos=(uchar*) key;
  208.     key+=seg->length;
  209.     if (seg->type == HA_KEYTYPE_TEXT)
  210.     {
  211.       for (; pos < (uchar*) key ; pos++)
  212.       {
  213. nr *=16777619; 
  214. nr ^=((uint) my_sort_order[(uint) *pos]);
  215.       }
  216.     }
  217.     else
  218.     {
  219.       for ( ; pos < (uchar*) key ; pos++)
  220.       {
  221. nr *=16777619; 
  222. nr ^=(uint) *pos;
  223.       }
  224.     }
  225.   }
  226.   return((ulong) nr);
  227. }
  228. /* Calc hashvalue for a key in a record */
  229. ulong _hp_rec_hashnr(register HP_KEYDEF *keydef, register const byte *rec)
  230. {
  231.   register ulong nr=0;
  232.   HP_KEYSEG *seg,*endseg;
  233.   for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
  234.   {
  235.     uchar *pos=(uchar*) rec+seg->start,*end=pos+seg->length;
  236.     if (seg->type == HA_KEYTYPE_TEXT)
  237.     {
  238.       for ( ; pos < end ; pos++)
  239.       {
  240. nr *=16777619; 
  241. nr ^=(uint) my_sort_order[(uint) *pos];
  242.       }
  243.     }
  244.     else
  245.     {
  246.       for ( ; pos < end ; pos++)
  247.       {
  248. nr *=16777619; 
  249. nr ^=(uint) *pos;
  250.       }
  251.     }
  252.   }
  253.   return((ulong) nr);
  254. }
  255. #endif
  256. /* Compare keys for two records. Returns 0 if they are identical */
  257. int _hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2)
  258. {
  259.   HP_KEYSEG *seg,*endseg;
  260.   for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
  261.   {
  262.     if (seg->type == HA_KEYTYPE_TEXT)
  263.     {
  264.       if (my_sortcmp(rec1+seg->start,rec2+seg->start,seg->length))
  265. return 1;
  266.     }
  267.     else
  268.     {
  269.       if (bcmp(rec1+seg->start,rec2+seg->start,seg->length))
  270. return 1;
  271.     }
  272.   }
  273.   return 0;
  274. }
  275. /* Compare a key in a record to a hole key */
  276. int _hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key)
  277. {
  278.   HP_KEYSEG *seg,*endseg;
  279.   for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
  280.   {
  281.     if (seg->type == HA_KEYTYPE_TEXT)
  282.     {
  283.       if (my_sortcmp(rec+seg->start,key,seg->length))
  284. return 1;
  285.     }
  286.     else
  287.     {
  288.       if (bcmp(rec+seg->start,key,seg->length))
  289. return 1;
  290.     }
  291.     key+=seg->length;
  292.   }
  293.   return 0;
  294. }
  295. /* Copy a key from a record to a keybuffer */
  296. void _hp_make_key(HP_KEYDEF *keydef, byte *key, const byte *rec)
  297. {
  298.   HP_KEYSEG *seg,*endseg;
  299.   for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
  300.   {
  301.     memcpy(key,rec+seg->start,(size_t) seg->length);
  302.     key+=seg->length;
  303.   }
  304. }