1
/* Copyright (C) 2003 MySQL AB
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; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
#include <ndb_types.h>
21
#define SEGMENTSIZE 64
22
#define SEGMENTLOGSIZE 6
23
#define DIRECTORYSIZE 64
24
#define DIRINDEX(adress) ((adress) >> SEGMENTLOGSIZE)
25
#define SEGINDEX(adress) ((adress) & (SEGMENTSIZE-1))
27
#if !defined(MAXLOADFCTR)
30
#if !defined(MINLOADFCTR)
31
#define MINLOADFCTR (MAXLOADFCTR/2)
44
NdbElement_t<C> *next;
47
NdbElement_t(const NdbElement_t<C> & aElement_t);
48
NdbElement_t & operator = (const NdbElement_t<C> & aElement_t);
57
void createHashTable(void);
58
void releaseHashTable(void);
60
int insertKey(const char * str, Uint32 len, Uint32 lkey1, C* data);
61
C *deleteKey(const char * str, Uint32 len);
63
C* getData(const char *, Uint32);
64
Uint32* getKey(const char *, Uint32);
66
void shrinkTable(void);
67
void expandHashTable(void);
69
Uint32 Hash(const char *str, Uint32 len);
70
Uint32 Hash(Uint32 h);
72
NdbElement_t<C> * getNext(NdbElement_t<C> * curr);
75
void getBucket(Uint32 hash, int * dirindex, int * segindex);
78
NdbElement_t<C> * elements[SEGMENTSIZE];
81
Uint32 p; /*bucket to be split*/
82
Uint32 max; /*max is the upper bound*/
83
Int32 slack; /*number of insertions before splits*/
84
Segment_t * directory[DIRECTORYSIZE];
86
NdbLinHash(const NdbLinHash<C> & aLinHash);
87
NdbLinHash<C> & operator = (const NdbLinHash<C> & aLinHash);
90
// All template methods must be inline
94
NdbLinHash<C>::NdbLinHash() {
99
NdbLinHash<C>::NdbLinHash(const NdbLinHash<C>& aLinHash)
105
NdbLinHash<C>::~NdbLinHash()
112
NdbLinHash<C>::Hash( const char* str, Uint32 len )
116
h = (h << 5) + h + str[0];
117
h = (h << 5) + h + str[1];
118
h = (h << 5) + h + str[2];
119
h = (h << 5) + h + str[3];
125
h = (h << 5) + h + *str++;
134
NdbLinHash<C>::Hash( Uint32 h ){
140
NdbElement_t<C>::NdbElement_t() :
152
NdbElement_t<C>::~NdbElement_t()
158
/* Initialize the hashtable HASH_T */
162
NdbLinHash<C>::createHashTable() {
164
max = SEGMENTSIZE - 1;
165
slack = SEGMENTSIZE * MAXLOADFCTR;
166
directory[0] = new Segment_t();
169
/* The first segment cleared before used */
170
for(i = 0; i < SEGMENTSIZE; i++ )
171
directory[0]->elements[i] = 0;
173
/* clear the rest of the directory */
174
for(i = 1; i < DIRECTORYSIZE; i++)
181
NdbLinHash<C>::getBucket(Uint32 hash, int * dir, int * seg){
182
Uint32 adress = hash & max;
184
adress = hash & (2 * max + 1);
186
* dir = DIRINDEX(adress);
187
* seg = SEGINDEX(adress);
193
NdbLinHash<C>::insertKey( const char* str, Uint32 len, Uint32 lkey1, C* data )
195
const Uint32 hash = Hash(str, len);
197
getBucket(hash, &dir, &seg);
199
NdbElement_t<C> **chainp = &directory[dir]->elements[seg];
202
* Check if the string already are in the hash table
203
* chain=chainp will copy the contents of HASH_T into chain
205
NdbElement_t<C> * oldChain = 0;
206
NdbElement_t<C> * chain;
207
for(chain = *chainp; chain != 0; chain = chain->next){
208
if(chain->len == len && !memcmp(chain->str, str, len))
209
return -1; /* Element already exists */
215
chain = new NdbElement_t<C>();
218
chain->localkey1 = lkey1;
220
chain->theData = data;
221
len++; // Null terminated
222
chain->str = new Uint32[((len + 3) >> 2)];
223
memcpy( &chain->str[0], str, len);
225
oldChain->next = chain;
234
return chain->localkey1;
241
NdbLinHash<C>::getKey( const char* str, Uint32 len )
243
const Uint32 tHash = Hash(str, len);
245
getBucket(tHash, &dir, &seg);
247
NdbElement_t<C> ** keyp = &directory[dir]->elements[seg];
249
/*Check if the string are in the hash table*/
250
for(NdbElement_t<C> * key = *keyp; key != 0; key = key->next ) {
251
if(key->len == len && !memcmp(key->str, str, len)) {
252
return &key->localkey1;
255
return NULL ; /* The key was not found */
261
NdbLinHash<C>::getData( const char* str, Uint32 len ){
263
const Uint32 tHash = Hash(str, len);
265
getBucket(tHash, &dir, &seg);
267
NdbElement_t<C> ** keyp = &directory[dir]->elements[seg];
269
/*Check if the string are in the hash table*/
270
for(NdbElement_t<C> * key = *keyp; key != 0; key = key->next ) {
271
if(key->len == len && !memcmp(key->str, str, len)) {
275
return NULL ; /* The key was not found */
281
NdbLinHash<C>::deleteKey ( const char* str, Uint32 len){
282
const Uint32 hash = Hash(str, len);
284
getBucket(hash, &dir, &seg);
286
NdbElement_t<C> *oldChain = 0;
287
NdbElement_t<C> **chainp = &directory[dir]->elements[seg];
288
for(NdbElement_t<C> * chain = *chainp; chain != 0; chain = chain->next){
289
if(chain->len == len && !memcmp(chain->str, str, len)){
290
C *data= chain->theData;
292
* chainp = chain->next;
294
oldChain->next = chain->next;
302
return 0; /* Element doesn't exist */
308
NdbLinHash<C>::releaseHashTable( void ){
309
NdbElement_t<C>* tNextElement;
310
NdbElement_t<C>* tElement;
312
//Traverse the whole directory structure
313
for(int countd = 0; countd < DIRECTORYSIZE;countd++ ){
314
if (directory[countd] != 0) {
315
//Traverse whole hashtable
316
for(int counts = 0; counts < SEGMENTSIZE; counts++ )
317
if (directory[countd]->elements[counts] != 0) {
318
tElement = directory[countd]->elements[counts];
319
//Delete all elements even those who is linked
321
tNextElement = tElement->next;
323
tElement = tNextElement;
324
} while (tNextElement != 0);
326
delete directory[countd];
334
NdbLinHash<C>::shrinkTable( void )
337
NdbElement_t<C> **chainp;
338
Uint32 oldlast = p + max;
343
// Adjust the state variables.
351
// Update slack after shrink.
353
slack -= MAXLOADFCTR;
355
// Insert the chain oldlast at the end of chain p.
357
chainp = &directory[DIRINDEX(p)]->elements[SEGINDEX(p)];
358
while( *chainp != 0 ) {
359
chainp = &((*chainp)->next);
360
lastseg = directory[DIRINDEX(oldlast)];
361
*chainp = lastseg->elements[SEGINDEX(oldlast)];
363
// If necessary free last segment.
364
if( SEGINDEX(oldlast) == 0)
372
NdbLinHash<C>::expandHashTable( void )
375
NdbElement_t<C> **oldbucketp, *chain, *headofold, *headofnew, *next;
376
Uint32 maxp = max + 1;
377
Uint32 newadress = maxp + p;
380
// Still room in the adress space?
381
if( newadress >= DIRECTORYSIZE * SEGMENTSIZE ) {
385
// If necessary, create a new segment.
386
if( SEGINDEX(newadress) == 0 )
387
directory[DIRINDEX(newadress)] = new Segment_t();
389
// Locate the old (to be split) bucket.
390
oldbucketp = &directory[DIRINDEX(p)]->elements[SEGINDEX(p)];
392
// Adjust the state variables.
399
// Update slack after expandation.
400
slack += MAXLOADFCTR;
402
// Relocate records to the new bucket.
406
for( chain = *oldbucketp; chain != 0; chain = next ) {
408
if( chain->hash & maxp ) {
409
chain->next = headofnew;
413
chain->next = headofold;
417
*oldbucketp = headofold;
418
directory[DIRINDEX(newadress)]->elements[SEGINDEX(newadress)] = headofnew;
424
NdbLinHash<C>::getNext(NdbElement_t<C> * curr){
425
if(curr != 0 && curr->next != 0)
428
int dir = 0, seg = 0;
432
getBucket(curr->hash, &dir, &seg);
440
for(int countd = dir; countd < DIRECTORYSIZE;countd++ ){
441
if (directory[countd] != 0) {
442
for(; counts < SEGMENTSIZE; counts++ ){
443
if (directory[countd]->elements[counts] != 0) {
444
return directory[countd]->elements[counts];