~drizzle-trunk/drizzle/development

520.7.1 by Monty Taylor
Moved hash.c to drizzled.
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; version 2 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
19
20
/* The hash functions used for saving keys */
1 by brian
clean slate
21
/* One of key_length or key_length_offset must be given */
22
/* Key length of 0 isn't allowed */
23
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
24
#include <config.h>
25
#include <drizzled/my_hash.h>
26
#include <drizzled/charset.h>
2221.7.5 by Olaf van der Spek
Refactor
27
#include <vector>
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
28
2221.7.5 by Olaf van der Spek
Refactor
29
namespace drizzled {
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
30
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
31
const uint32_t NO_RECORD= UINT32_MAX;
32
33
const int LOWFIND= 1;
34
const int LOWUSED= 2;
35
const int HIGHFIND= 4;
36
const int HIGHUSED= 8;
1 by brian
clean slate
37
2221.7.5 by Olaf van der Spek
Refactor
38
static uint32_t hash_mask(uint32_t hashnr, uint32_t buffmax, uint32_t maxlength);
39
static void movelink(HASH_LINK *array, uint32_t pos, uint32_t next_link, uint32_t newlink);
40
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key, size_t length);
41
42
static uint32_t calc_hash(const HASH *hash, const unsigned char *key, size_t length)
1 by brian
clean slate
43
{
290 by Brian Aker
Update for ulong change over.
44
  uint32_t nr1=1, nr2=4;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
45
  hash->charset->coll->hash_sort(hash->charset, key,length, &nr1, &nr2);
1 by brian
clean slate
46
  return nr1;
47
}
48
2210.3.6 by Olaf van der Spek
Use push_back
49
#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
50
2318.4.9 by Olaf van der Spek
Refactor
51
void
2254 by Brian Aker
Shift CHARSET_INFO to charset_info_st
52
_hash_init(HASH *hash,uint32_t growth_size, const charset_info_st * const charset,
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
53
           uint32_t size, size_t key_offset, size_t key_length,
54
           hash_get_key get_key,
598.1.1 by Super-User
Fixed solaris build crap.
55
           hash_free_key free_element, uint32_t flags)
1 by brian
clean slate
56
{
57
  hash->records=0;
2385.3.7 by Olaf van der Spek
Refactor DYNAMIC_ARRAY
58
  hash->array.init(sizeof(HASH_LINK), size, growth_size);
1 by brian
clean slate
59
  hash->key_offset=key_offset;
60
  hash->key_length=key_length;
61
  hash->blength=1;
62
  hash->get_key=get_key;
63
  hash->free=free_element;
64
  hash->flags=flags;
65
  hash->charset=charset;
66
}
67
68
69
/*
70
  Call hash->free on all elements in hash.
71
72
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
73
  hash_free_elements()
74
  hash   hash table
1 by brian
clean slate
75
76
  NOTES:
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
77
  Sets records to 0
1 by brian
clean slate
78
*/
79
80
static inline void hash_free_elements(HASH *hash)
81
{
82
  if (hash->free)
83
  {
84
    HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
85
    HASH_LINK *end= data + hash->records;
86
    while (data < end)
87
      (*hash->free)((data++)->data);
88
  }
89
  hash->records=0;
90
}
91
92
93
/*
94
  Free memory used by hash.
95
96
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
97
  hash_free()
98
  hash   the hash to delete elements of
1 by brian
clean slate
99
100
  NOTES: Hash can't be reused without calling hash_init again.
101
*/
102
103
void hash_free(HASH *hash)
104
{
105
  hash_free_elements(hash);
106
  hash->free= 0;
2385.3.7 by Olaf van der Spek
Refactor DYNAMIC_ARRAY
107
  hash->array.free();
1 by brian
clean slate
108
}
109
110
/* some helper functions */
111
112
/*
481 by Brian Aker
Remove all of uchar.
113
  This function is char* instead of unsigned char* as HPUX11 compiler can't
1 by brian
clean slate
114
  handle inline functions that are not defined as native types
115
*/
116
117
static inline char*
481 by Brian Aker
Remove all of uchar.
118
hash_key(const HASH *hash, const unsigned char *record, size_t *length,
146 by Brian Aker
my_bool cleanup.
119
         bool first)
1 by brian
clean slate
120
{
121
  if (hash->get_key)
122
    return (char*) (*hash->get_key)(record,length,first);
123
  *length=hash->key_length;
124
  return (char*) record+hash->key_offset;
125
}
126
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
127
/* Calculate pos according to keys */
1 by brian
clean slate
128
482 by Brian Aker
Remove uint.
129
static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength)
1 by brian
clean slate
130
{
131
  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
132
  return (hashnr & ((buffmax >> 1) -1));
133
}
134
482 by Brian Aker
Remove uint.
135
static uint32_t hash_rec_mask(const HASH *hash, HASH_LINK *pos,
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
136
                              uint32_t buffmax, uint32_t maxlength)
1 by brian
clean slate
137
{
138
  size_t length;
481 by Brian Aker
Remove all of uchar.
139
  unsigned char *key= (unsigned char*) hash_key(hash,pos->data,&length,0);
1 by brian
clean slate
140
  return hash_mask(calc_hash(hash,key,length),buffmax,maxlength);
141
}
142
143
144
145
static
146
inline
481 by Brian Aker
Remove all of uchar.
147
unsigned int rec_hashnr(HASH *hash,const unsigned char *record)
1 by brian
clean slate
148
{
149
  size_t length;
481 by Brian Aker
Remove all of uchar.
150
  unsigned char *key= (unsigned char*) hash_key(hash,record,&length,0);
1 by brian
clean slate
151
  return calc_hash(hash,key,length);
152
}
153
154
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
155
unsigned char* hash_search(const HASH *hash, const unsigned char *key,
156
                           size_t length)
1 by brian
clean slate
157
{
158
  HASH_SEARCH_STATE state;
159
  return hash_first(hash, key, length, &state);
160
}
161
162
/*
163
  Search after a record based on a key
164
165
  NOTE
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
166
  Assigns the number of the found record to HASH_SEARCH_STATE state
1 by brian
clean slate
167
*/
168
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
169
unsigned char* hash_first(const HASH *hash, const unsigned char *key,
170
                          size_t length,
171
                          HASH_SEARCH_STATE *current_record)
1 by brian
clean slate
172
{
173
  HASH_LINK *pos;
482 by Brian Aker
Remove uint.
174
  uint32_t flag,idx;
1 by brian
clean slate
175
176
  flag=1;
177
  if (hash->records)
178
  {
179
    idx=hash_mask(calc_hash(hash,key,length ? length : hash->key_length),
1138 by Brian Aker
Merge of Joe Daly's work
180
                  hash->blength,hash->records);
1 by brian
clean slate
181
    do
182
    {
183
      pos= dynamic_element(&hash->array,idx,HASH_LINK*);
184
      if (!hashcmp(hash,pos,key,length))
185
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
186
        *current_record= idx;
187
        return (pos->data);
1 by brian
clean slate
188
      }
189
      if (flag)
190
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
191
        /* Reset flag */
192
        flag=0;
1138 by Brian Aker
Merge of Joe Daly's work
193
        if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
194
          /* Wrong link */
195
          break;
1 by brian
clean slate
196
      }
197
    }
198
    while ((idx=pos->next) != NO_RECORD);
199
  }
200
  *current_record= NO_RECORD;
2318.6.58 by Olaf van der Spek
Refactor
201
  return 0;
1 by brian
clean slate
202
}
203
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
204
/* Change link from pos to new_link */
1 by brian
clean slate
205
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
206
static void movelink(HASH_LINK *array, uint32_t find,
207
                     uint32_t next_link, uint32_t newlink)
1 by brian
clean slate
208
{
209
  HASH_LINK *old_link;
210
  do
211
  {
212
    old_link=array+next_link;
213
  }
214
  while ((next_link=old_link->next) != find);
215
  old_link->next= newlink;
216
  return;
217
}
218
219
/*
220
  Compare a key in a record to a whole key. Return 0 if identical
221
222
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
223
  hashcmp()
224
  hash   hash table
225
  pos    position of hash record to use in comparison
226
  key    key for comparison
227
  length length of key
1 by brian
clean slate
228
229
  NOTES:
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
230
  If length is 0, comparison is done using the length of the
231
  record being compared against.
1 by brian
clean slate
232
233
  RETURN
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
234
  = 0  key of record == key
235
  != 0 key of record != key
236
*/
1 by brian
clean slate
237
481 by Brian Aker
Remove all of uchar.
238
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
1 by brian
clean slate
239
                   size_t length)
240
{
241
  size_t rec_keylength;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
242
  unsigned char *rec_key= (unsigned char*) hash_key(hash, pos->data,
243
                                                    &rec_keylength,1);
1 by brian
clean slate
244
  return ((length && length != rec_keylength) ||
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
245
          my_strnncoll(hash->charset, rec_key, rec_keylength,
246
                       key, rec_keylength));
1 by brian
clean slate
247
}
248
249
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
250
/* Write a hash-key to the hash-index */
1 by brian
clean slate
251
481 by Brian Aker
Remove all of uchar.
252
bool my_hash_insert(HASH *info,const unsigned char *record)
1 by brian
clean slate
253
{
254
  int flag;
255
  size_t idx;
482 by Brian Aker
Remove uint.
256
  uint32_t halfbuff,hash_nr,first_index;
481 by Brian Aker
Remove all of uchar.
257
  unsigned char *ptr_to_rec=NULL,*ptr_to_rec2=NULL;
77.1.71 by Monty Taylor
Uninitialized use.
258
  HASH_LINK *data,*empty,*gpos=NULL,*gpos2=NULL,*pos;
1 by brian
clean slate
259
260
  if (HASH_UNIQUE & info->flags)
261
  {
481 by Brian Aker
Remove all of uchar.
262
    unsigned char *key= (unsigned char*) hash_key(info, record, &idx, 1);
1 by brian
clean slate
263
    if (hash_search(info, key, idx))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
264
      /* Duplicate entry */
2318.6.55 by Olaf van der Spek
Refactor
265
      return true;
1 by brian
clean slate
266
  }
267
268
  flag=0;
2385.3.7 by Olaf van der Spek
Refactor DYNAMIC_ARRAY
269
  empty=(HASH_LINK*)info->array.alloc();
1 by brian
clean slate
270
271
  data=dynamic_element(&info->array,0,HASH_LINK*);
1138 by Brian Aker
Merge of Joe Daly's work
272
  halfbuff= info->blength >> 1;
1 by brian
clean slate
273
1138 by Brian Aker
Merge of Joe Daly's work
274
  idx= first_index= info->records-halfbuff;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
275
  /* If some records */
276
  if (idx != info->records)
1 by brian
clean slate
277
  {
278
    do
279
    {
280
      pos=data+idx;
281
      hash_nr=rec_hashnr(info,pos->data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
282
      /* First loop; Check if ok */
283
      if (flag == 0)
1138 by Brian Aker
Merge of Joe Daly's work
284
        if (hash_mask(hash_nr,info->blength,info->records) != first_index)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
285
          break;
1 by brian
clean slate
286
      if (!(hash_nr & halfbuff))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
287
      {
288
        /* Key will not move */
289
        if (!(flag & LOWFIND))
290
        {
291
          if (flag & HIGHFIND)
292
          {
293
            flag=LOWFIND | HIGHFIND;
294
            /* key shall be moved to the current empty position */
295
            gpos=empty;
296
            ptr_to_rec=pos->data;
297
            /* This place is now free */
298
            empty=pos;
299
          }
300
          else
301
          {
302
            /* key isn't changed */
303
            flag=LOWFIND | LOWUSED;
304
            gpos=pos;
305
            ptr_to_rec=pos->data;
306
          }
307
        }
308
        else
309
        {
310
          if (!(flag & LOWUSED))
311
          {
312
            /* Change link of previous LOW-key */
313
            gpos->data=ptr_to_rec;
895 by Brian Aker
Completion (?) of uint conversion.
314
            gpos->next= (uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
315
            flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
316
          }
317
          gpos=pos;
318
          ptr_to_rec=pos->data;
319
        }
1 by brian
clean slate
320
      }
321
      else
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
322
      {
323
        /* key will be moved */
324
        if (!(flag & HIGHFIND))
325
        {
326
          flag= (flag & LOWFIND) | HIGHFIND;
327
          /* key shall be moved to the last (empty) position */
328
          gpos2 = empty; empty=pos;
329
          ptr_to_rec2=pos->data;
330
        }
331
        else
332
        {
333
          if (!(flag & HIGHUSED))
334
          {
335
            /* Change link of previous hash-key and save */
336
            gpos2->data=ptr_to_rec2;
895 by Brian Aker
Completion (?) of uint conversion.
337
            gpos2->next=(uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
338
            flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
339
          }
340
          gpos2=pos;
341
          ptr_to_rec2=pos->data;
342
        }
1 by brian
clean slate
343
      }
344
    }
345
    while ((idx=pos->next) != NO_RECORD);
346
347
    if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
348
    {
349
      gpos->data=ptr_to_rec;
350
      gpos->next=NO_RECORD;
351
    }
352
    if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
353
    {
354
      gpos2->data=ptr_to_rec2;
355
      gpos2->next=NO_RECORD;
356
    }
357
  }
358
  /* Check if we are at the empty position */
359
1138 by Brian Aker
Merge of Joe Daly's work
360
  idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
1 by brian
clean slate
361
  pos=data+idx;
362
  if (pos == empty)
363
  {
481 by Brian Aker
Remove all of uchar.
364
    pos->data=(unsigned char*) record;
1 by brian
clean slate
365
    pos->next=NO_RECORD;
366
  }
367
  else
368
  {
369
    /* Check if more records in same hash-nr family */
370
    empty[0]=pos[0];
1138 by Brian Aker
Merge of Joe Daly's work
371
    gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
1 by brian
clean slate
372
    if (pos == gpos)
373
    {
481 by Brian Aker
Remove all of uchar.
374
      pos->data=(unsigned char*) record;
895 by Brian Aker
Completion (?) of uint conversion.
375
      pos->next=(uint32_t) (empty - data);
1 by brian
clean slate
376
    }
377
    else
378
    {
481 by Brian Aker
Remove all of uchar.
379
      pos->data=(unsigned char*) record;
1 by brian
clean slate
380
      pos->next=NO_RECORD;
895 by Brian Aker
Completion (?) of uint conversion.
381
      movelink(data,(uint32_t) (pos-data),(uint32_t) (gpos-data),(uint32_t) (empty-data));
1 by brian
clean slate
382
    }
383
  }
384
  if (++info->records == info->blength)
385
    info->blength+= info->blength;
2318.6.58 by Olaf van der Spek
Refactor
386
  return 0;
1 by brian
clean slate
387
}
388
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
389
} /* namespace drizzled */