NdbLinHash.hpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:10k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #ifndef NdbLinHash_H
  14. #define NdbLinHash_H
  15. #include <ndb_types.h>
  16. #define SEGMENTSIZE 64
  17. #define SEGMENTLOGSIZE 6
  18. #define DIRECTORYSIZE 64
  19. #define DIRINDEX(adress) ((adress) >> SEGMENTLOGSIZE)
  20. #define SEGINDEX(adress) ((adress) & (SEGMENTSIZE-1))
  21. #if     !defined(MAXLOADFCTR)
  22. #define MAXLOADFCTR 2
  23. #endif
  24. #if     !defined(MINLOADFCTR)
  25. #define MINLOADFCTR (MAXLOADFCTR/2)
  26. #endif
  27. template<class C> 
  28. class NdbElement_t {
  29. public:
  30.   NdbElement_t();
  31.   ~NdbElement_t();
  32.   
  33.   Uint32 len;
  34.   Uint32 hash;
  35.   Uint32 localkey1;
  36.   Uint32 *str;
  37.   NdbElement_t<C> *next;
  38.   C* theData;
  39. private:
  40.   NdbElement_t(const NdbElement_t<C> & aElement_t);
  41.   NdbElement_t & operator = (const NdbElement_t<C> & aElement_t);
  42. };
  43. template <class C> 
  44. class NdbLinHash {
  45. public:
  46.   NdbLinHash();
  47.   ~NdbLinHash();
  48.   void createHashTable(void);
  49.   void releaseHashTable(void);
  50.   
  51.   int insertKey(const char * str, Uint32 len, Uint32 lkey1, C* data);
  52.   C *deleteKey(const char * str, Uint32 len);
  53.   C* getData(const char *, Uint32);
  54.   Uint32* getKey(const char *, Uint32);
  55.   
  56.   void shrinkTable(void);
  57.   void expandHashTable(void);
  58.   
  59.   Uint32 Hash(const char *str, Uint32 len);
  60.   Uint32 Hash(Uint32 h);
  61.   
  62.   NdbElement_t<C> * getNext(NdbElement_t<C> * curr);
  63.   
  64. private:
  65.   void getBucket(Uint32 hash, int * dirindex, int * segindex);
  66.   
  67.   struct Segment_t {
  68.     NdbElement_t<C> * elements[SEGMENTSIZE];
  69.   };
  70.   Uint32 p; /*bucket to be split*/
  71.   Uint32 max; /*max is the upper bound*/
  72.   Int32  slack; /*number of insertions before splits*/
  73.   Segment_t * directory[DIRECTORYSIZE];
  74.   
  75.   NdbLinHash(const NdbLinHash<C> & aLinHash);
  76.   NdbLinHash<C> & operator = (const NdbLinHash<C> & aLinHash);
  77. };
  78. // All template methods must be inline
  79. template <class C>
  80. inline
  81. NdbLinHash<C>::NdbLinHash() { 
  82. }
  83. template <class C>
  84. inline
  85. NdbLinHash<C>::NdbLinHash(const NdbLinHash<C>& aLinHash) 
  86. {
  87. }
  88. template <class C>
  89. inline
  90. NdbLinHash<C>::~NdbLinHash()
  91. {
  92. }
  93. template <class C>
  94. inline
  95. Uint32
  96. NdbLinHash<C>::Hash( const char* str, Uint32 len )
  97. {
  98.   Uint32 h = 0;
  99.   while(len >= 4){
  100.     h = (h << 5) + h + str[0];
  101.     h = (h << 5) + h + str[1];
  102.     h = (h << 5) + h + str[2];
  103.     h = (h << 5) + h + str[3];
  104.     len -= 4;
  105.     str += 4;
  106.   }
  107.   
  108.   while(len > 0){
  109.     h = (h << 5) + h + *str++;
  110.     len--;
  111.   }
  112.   return h;
  113. }
  114. template <class C>
  115. inline
  116. Uint32
  117. NdbLinHash<C>::Hash( Uint32 h ){
  118.   return h;
  119. }
  120. template <class C>
  121. inline
  122. NdbElement_t<C>::NdbElement_t() :
  123.   len(0),
  124.   hash(0),
  125.   localkey1(0),
  126.   str(NULL),
  127.   next(NULL),
  128.   theData(NULL)
  129. }
  130. template <class C>
  131. inline
  132. NdbElement_t<C>::~NdbElement_t()
  133. {
  134.   delete []str;
  135. }
  136. /* Initialize the hashtable HASH_T  */
  137. template <class C>
  138. inline
  139. void
  140. NdbLinHash<C>::createHashTable() {
  141.   p = 0;
  142.   max = SEGMENTSIZE - 1;
  143.   slack = SEGMENTSIZE * MAXLOADFCTR;
  144.   directory[0] = new Segment_t();
  145.   int i;
  146.  
  147.   /* The first segment cleared before used */
  148.   for(i  = 0; i < SEGMENTSIZE; i++ )
  149.     directory[0]->elements[i] = 0;
  150.   
  151.   /* clear the rest of the directory */
  152.   for(i = 1; i < DIRECTORYSIZE; i++)
  153.     directory[i] = 0;
  154. }
  155. template <class C>
  156. inline
  157. void
  158. NdbLinHash<C>::getBucket(Uint32 hash, int * dir, int * seg){
  159.   Uint32 adress = hash & max;
  160.   if(adress < p)
  161.     adress = hash & (2 * max + 1);
  162.   
  163.   * dir = DIRINDEX(adress);
  164.   * seg = SEGINDEX(adress);
  165. }
  166. template <class C>
  167. inline
  168. Int32
  169. NdbLinHash<C>::insertKey( const char* str, Uint32 len, Uint32 lkey1, C* data )
  170. {
  171.   const Uint32 hash = Hash(str, len);
  172.   int dir, seg;
  173.   getBucket(hash, &dir, &seg);
  174.   
  175.   NdbElement_t<C> **chainp = &directory[dir]->elements[seg];
  176.   
  177.   /**
  178.    * Check if the string already are in the hash table
  179.    * chain=chainp will copy the contents of HASH_T into chain  
  180.    */
  181.   NdbElement_t<C> * oldChain = 0;  
  182.   NdbElement_t<C> * chain;
  183.   for(chain = *chainp; chain != 0; chain = chain->next){
  184.     if(chain->len == len && !memcmp(chain->str, str, len)) 
  185.       return -1; /* Element already exists */
  186.     else 
  187.       oldChain = chain;
  188.   }
  189.   /* New entry */
  190.   chain = new NdbElement_t<C>();
  191.   chain->len = len;
  192.   chain->hash = hash;
  193.   chain->localkey1 = lkey1;
  194.   chain->next = 0;
  195.   chain->theData = data;
  196.   chain->str = new Uint32[((len + 3) >> 2)];
  197.   memcpy( &chain->str[0], str, len );
  198.   if (oldChain != 0) 
  199.     oldChain->next = chain;
  200.   else
  201.     *chainp =  chain; 
  202.   
  203. #if 0
  204.   if(--(slack) < 0)
  205.     expandHashTable(); 
  206. #endif
  207.   
  208.   return chain->localkey1;
  209. }
  210. template <class C>
  211. inline
  212. Uint32*
  213. NdbLinHash<C>::getKey( const char* str, Uint32 len )
  214. {
  215.   const Uint32 tHash = Hash(str, len);
  216.   int dir, seg;
  217.   getBucket(tHash, &dir, &seg);
  218.   
  219.   NdbElement_t<C> ** keyp = &directory[dir]->elements[seg];
  220.   
  221.   /*Check if the string are in the hash table*/
  222.   for(NdbElement_t<C> * key = *keyp; key != 0; key = key->next ) {
  223.     if(key->len == len && !memcmp(key->str, str, len)) {
  224.       return &key->localkey1;  
  225.     }
  226.   }
  227.   return NULL ; /* The key was not found */
  228. }
  229. template <class C>
  230. inline
  231. C*
  232. NdbLinHash<C>::getData( const char* str, Uint32 len ){
  233.   
  234.   const Uint32 tHash = Hash(str, len);
  235.   int dir, seg;
  236.   getBucket(tHash, &dir, &seg);
  237.   
  238.   NdbElement_t<C> ** keyp = &directory[dir]->elements[seg];
  239.     
  240.   /*Check if the string are in the hash table*/
  241.   for(NdbElement_t<C> * key = *keyp; key != 0; key = key->next ) {
  242.     if(key->len == len && !memcmp(key->str, str, len)) {
  243.       return key->theData;  
  244.     }
  245.   }
  246.   return NULL ; /* The key was not found */
  247. }
  248. template <class C>
  249. inline
  250. C *
  251. NdbLinHash<C>::deleteKey ( const char* str, Uint32 len){
  252.   const Uint32 hash = Hash(str, len);
  253.   int dir, seg;
  254.   getBucket(hash, &dir, &seg);
  255.   
  256.   NdbElement_t<C> *oldChain = 0;
  257.   NdbElement_t<C> **chainp = &directory[dir]->elements[seg];
  258.   for(NdbElement_t<C> * chain = *chainp; chain != 0; chain = chain->next){
  259.     if(chain->len == len && !memcmp(chain->str, str, len)){
  260.       C *data= chain->theData;
  261.       if (oldChain == 0) {
  262. * chainp = chain->next;
  263.       } else {
  264. oldChain->next = chain->next;
  265.       }
  266.       delete chain;
  267.       return data;
  268.     } else {
  269.       oldChain = chain;
  270.     }
  271.   }
  272.   return 0; /* Element doesn't exist */
  273. }
  274. template <class C>
  275. inline
  276. void 
  277. NdbLinHash<C>::releaseHashTable( void ){
  278.   NdbElement_t<C>* tNextElement;
  279.   NdbElement_t<C>* tElement;
  280.   
  281.   //Traverse the whole directory structure
  282.   for(int countd = 0; countd < DIRECTORYSIZE;countd++ ){
  283.     if (directory[countd] != 0) {
  284.       //Traverse whole hashtable
  285.       for(int counts = 0; counts < SEGMENTSIZE; counts++ )
  286. if (directory[countd]->elements[counts] != 0) {
  287.   tElement = directory[countd]->elements[counts];
  288.   //Delete all elements even those who is linked
  289.   do {
  290.     tNextElement = tElement->next;        
  291.     delete tElement;
  292.     tElement = tNextElement;
  293.   } while (tNextElement != 0);
  294. }
  295.       delete directory[countd];
  296.     }   
  297.   }
  298. }
  299. template <class C>
  300. inline
  301. void
  302. NdbLinHash<C>::shrinkTable( void )
  303. {
  304.   Segment_t *lastseg;
  305.   NdbElement_t<C> **chainp;
  306.   Uint32 oldlast = p + max;
  307.   if( oldlast == 0 )
  308.     return;
  309.   // Adjust the state variables.
  310.   if( p == 0 ) {
  311.     max >>= 1;
  312.     p = max;
  313.   }
  314.   else
  315.     --(p);
  316.     
  317.   // Update slack after shrink.
  318.     
  319.   slack -= MAXLOADFCTR;
  320.   // Insert the chain oldlast at the end of chain p.
  321.     
  322.   chainp = &directory[DIRINDEX(p)]->elements[SEGINDEX(p)];
  323.   while( *chainp != 0 ) {
  324.     chainp = &((*chainp)->next);
  325.     lastseg = directory[DIRINDEX(oldlast)];
  326.     *chainp = lastseg->elements[SEGINDEX(oldlast)];
  327.     // If necessary free last segment.
  328.     if( SEGINDEX(oldlast) == 0)
  329.       delete lastseg;
  330.   }
  331. }
  332. template <class C>
  333. inline
  334. void 
  335. NdbLinHash<C>::expandHashTable( void )
  336. {
  337.   NdbElement_t<C> **oldbucketp, *chain, *headofold, *headofnew, *next;
  338.   Uint32 maxp = max + 1;
  339.   Uint32 newadress = maxp + p;
  340.   // Still room in the adress space?
  341.   if( newadress >= DIRECTORYSIZE * SEGMENTSIZE ) {
  342.     return;
  343.   }  
  344.   
  345.   // If necessary, create a new segment.
  346.   if( SEGINDEX(newadress) == 0 )
  347.     directory[DIRINDEX(newadress)] = new Segment_t();
  348.     
  349.   // Locate the old (to be split) bucket.
  350.   oldbucketp = &directory[DIRINDEX(p)]->elements[SEGINDEX(p)];
  351.     
  352.   // Adjust the state variables.
  353.   p++;      
  354.   if( p > max ) {
  355.     max = 2 *max + 1;
  356.     p = 0;
  357.   }
  358.     
  359.   // Update slack after expandation.
  360.   slack += MAXLOADFCTR;
  361.     
  362.   // Relocate records to the new bucket.
  363.   headofold = 0;
  364.   headofnew = 0;
  365.     
  366.   for( chain = *oldbucketp; chain != 0; chain = next ) {
  367.     next = chain->next;
  368.     if( chain->hash & maxp ) {
  369.       chain->next = headofnew;
  370.       headofnew = chain;
  371.     }
  372.     else {
  373.       chain->next = headofold;
  374.       headofold = chain;
  375.     }
  376.   }
  377.   *oldbucketp = headofold;
  378.   directory[DIRINDEX(newadress)]->elements[SEGINDEX(newadress)] = headofnew;
  379. }
  380. template <class C>
  381. inline
  382. NdbElement_t<C> *
  383. NdbLinHash<C>::getNext(NdbElement_t<C> * curr){
  384.   if(curr != 0 && curr->next != 0)
  385.     return curr->next;
  386.   
  387.   int dir = 0, seg = 0;
  388.   if(curr != 0){
  389.     getBucket(curr->hash, &dir, &seg);
  390.   }
  391.   
  392.   for(int countd = dir; countd < DIRECTORYSIZE;countd++ ){
  393.     if (directory[countd] != 0) {
  394.       for(int counts = seg + 1; counts < SEGMENTSIZE; counts++ ){
  395. if (directory[countd]->elements[counts] != 0) {
  396.   return directory[countd]->elements[counts];
  397. }   
  398.       }
  399.     }
  400.   }
  401.   return 0;
  402. }
  403. #endif