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