~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;
2318.4.8 by Olaf van der Spek
Remove malloc NULL check. Just die.
58
  my_init_dynamic_array_ci(&hash->array, 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;
107
  delete_dynamic(&hash->array);
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;
269
  if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
270
    /* No more memory */
2318.6.55 by Olaf van der Spek
Refactor
271
    return true;
1 by brian
clean slate
272
273
  data=dynamic_element(&info->array,0,HASH_LINK*);
1138 by Brian Aker
Merge of Joe Daly's work
274
  halfbuff= info->blength >> 1;
1 by brian
clean slate
275
1138 by Brian Aker
Merge of Joe Daly's work
276
  idx= first_index= info->records-halfbuff;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
277
  /* If some records */
278
  if (idx != info->records)
1 by brian
clean slate
279
  {
280
    do
281
    {
282
      pos=data+idx;
283
      hash_nr=rec_hashnr(info,pos->data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
284
      /* First loop; Check if ok */
285
      if (flag == 0)
1138 by Brian Aker
Merge of Joe Daly's work
286
        if (hash_mask(hash_nr,info->blength,info->records) != first_index)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
287
          break;
1 by brian
clean slate
288
      if (!(hash_nr & halfbuff))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
289
      {
290
        /* Key will not move */
291
        if (!(flag & LOWFIND))
292
        {
293
          if (flag & HIGHFIND)
294
          {
295
            flag=LOWFIND | HIGHFIND;
296
            /* key shall be moved to the current empty position */
297
            gpos=empty;
298
            ptr_to_rec=pos->data;
299
            /* This place is now free */
300
            empty=pos;
301
          }
302
          else
303
          {
304
            /* key isn't changed */
305
            flag=LOWFIND | LOWUSED;
306
            gpos=pos;
307
            ptr_to_rec=pos->data;
308
          }
309
        }
310
        else
311
        {
312
          if (!(flag & LOWUSED))
313
          {
314
            /* Change link of previous LOW-key */
315
            gpos->data=ptr_to_rec;
895 by Brian Aker
Completion (?) of uint conversion.
316
            gpos->next= (uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
317
            flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
318
          }
319
          gpos=pos;
320
          ptr_to_rec=pos->data;
321
        }
1 by brian
clean slate
322
      }
323
      else
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
324
      {
325
        /* key will be moved */
326
        if (!(flag & HIGHFIND))
327
        {
328
          flag= (flag & LOWFIND) | HIGHFIND;
329
          /* key shall be moved to the last (empty) position */
330
          gpos2 = empty; empty=pos;
331
          ptr_to_rec2=pos->data;
332
        }
333
        else
334
        {
335
          if (!(flag & HIGHUSED))
336
          {
337
            /* Change link of previous hash-key and save */
338
            gpos2->data=ptr_to_rec2;
895 by Brian Aker
Completion (?) of uint conversion.
339
            gpos2->next=(uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
340
            flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
341
          }
342
          gpos2=pos;
343
          ptr_to_rec2=pos->data;
344
        }
1 by brian
clean slate
345
      }
346
    }
347
    while ((idx=pos->next) != NO_RECORD);
348
349
    if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
350
    {
351
      gpos->data=ptr_to_rec;
352
      gpos->next=NO_RECORD;
353
    }
354
    if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
355
    {
356
      gpos2->data=ptr_to_rec2;
357
      gpos2->next=NO_RECORD;
358
    }
359
  }
360
  /* Check if we are at the empty position */
361
1138 by Brian Aker
Merge of Joe Daly's work
362
  idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
1 by brian
clean slate
363
  pos=data+idx;
364
  if (pos == empty)
365
  {
481 by Brian Aker
Remove all of uchar.
366
    pos->data=(unsigned char*) record;
1 by brian
clean slate
367
    pos->next=NO_RECORD;
368
  }
369
  else
370
  {
371
    /* Check if more records in same hash-nr family */
372
    empty[0]=pos[0];
1138 by Brian Aker
Merge of Joe Daly's work
373
    gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
1 by brian
clean slate
374
    if (pos == gpos)
375
    {
481 by Brian Aker
Remove all of uchar.
376
      pos->data=(unsigned char*) record;
895 by Brian Aker
Completion (?) of uint conversion.
377
      pos->next=(uint32_t) (empty - data);
1 by brian
clean slate
378
    }
379
    else
380
    {
481 by Brian Aker
Remove all of uchar.
381
      pos->data=(unsigned char*) record;
1 by brian
clean slate
382
      pos->next=NO_RECORD;
895 by Brian Aker
Completion (?) of uint conversion.
383
      movelink(data,(uint32_t) (pos-data),(uint32_t) (gpos-data),(uint32_t) (empty-data));
1 by brian
clean slate
384
    }
385
  }
386
  if (++info->records == info->blength)
387
    info->blength+= info->blength;
2318.6.58 by Olaf van der Spek
Refactor
388
  return 0;
1 by brian
clean slate
389
}
390
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
391
} /* namespace drizzled */