1
/* Copyright (C) 2000 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 */
16
/* The hash functions used for saveing keys */
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
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.
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.
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
20
/* The hash functions used for saving keys */
17
21
/* One of key_length or key_length_offset must be given */
18
22
/* Key length of 0 isn't allowed */
20
#include "mysys_priv.h"
21
#include <mystrings/m_string.h>
22
#include <mystrings/m_ctype.h>
25
#define NO_RECORD ((uint) -1)
25
#include <drizzled/definitions.h>
26
#include <drizzled/hash.h>
28
const uint32_t NO_RECORD= UINT32_MAX;
32
const int HIGHFIND= 4;
33
const int HIGHUSED= 8;
31
35
typedef struct st_hash_info {
32
uint32_t next; /* index to next key */
33
unsigned char *data; /* data for current entry */
36
/* index to next key */
38
/* data for current entry */
36
static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength);
37
static void movelink(HASH_LINK *array,uint32_t pos,uint32_t next_link,uint32_t newlink);
42
static uint32_t hash_mask(uint32_t hashnr, uint32_t buffmax,
44
static void movelink(HASH_LINK *array, uint32_t pos,
45
uint32_t next_link, uint32_t newlink);
38
46
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
41
static uint32_t calc_hash(const HASH *hash, const unsigned char *key, size_t length)
49
static uint32_t calc_hash(const HASH *hash, const unsigned char *key,
43
52
uint32_t nr1=1, nr2=4;
44
hash->charset->coll->hash_sort(hash->charset,(const unsigned char*) key,length,&nr1,&nr2);
53
hash->charset->coll->hash_sort(hash->charset, key,length, &nr1, &nr2);
49
58
_hash_init(HASH *hash,uint32_t growth_size, const CHARSET_INFO * const charset,
50
uint32_t size, size_t key_offset, size_t key_length,
52
void (*free_element)(void*),uint32_t flags CALLER_INFO_PROTO)
59
uint32_t size, size_t key_offset, size_t key_length,
61
void (*free_element)(void*),uint32_t flags CALLER_INFO_PROTO)
55
64
if (my_init_dynamic_array_ci(&hash->array, sizeof(HASH_LINK), size,
58
hash->free=0; /* Allow call to hash_free */
67
/* Allow call to hash_free */
61
71
hash->key_offset=key_offset;
200
209
if (hash->records)
202
211
idx=hash_mask(calc_hash(hash,key,length ? length : hash->key_length),
203
hash->blength,hash->records);
212
hash->blength,hash->records);
206
215
pos= dynamic_element(&hash->array,idx,HASH_LINK*);
207
216
if (!hashcmp(hash,pos,key,length))
209
*current_record= idx;
218
*current_record= idx;
214
flag=0; /* Reset flag */
215
if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
216
break; /* Wrong link */
225
if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
219
230
while ((idx=pos->next) != NO_RECORD);
267
280
Compare a key in a record to a whole key. Return 0 if identical
272
pos position of hash record to use in comparison
273
key key for comparison
285
pos position of hash record to use in comparison
286
key key for comparison
277
If length is 0, comparison is done using the length of the
278
record being compared against.
290
If length is 0, comparison is done using the length of the
291
record being compared against.
281
= 0 key of record == key
282
!= 0 key of record != key
294
= 0 key of record == key
295
!= 0 key of record != key
285
298
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
288
301
size_t rec_keylength;
289
unsigned char *rec_key= (unsigned char*) hash_key(hash,pos->data,&rec_keylength,1);
302
unsigned char *rec_key= (unsigned char*) hash_key(hash, pos->data,
290
304
return ((length && length != rec_keylength) ||
291
my_strnncoll(hash->charset, (const unsigned char*) rec_key, rec_keylength,
292
(const unsigned char*) key, rec_keylength));
305
my_strnncoll(hash->charset, rec_key, rec_keylength,
306
key, rec_keylength));
296
/* Write a hash-key to the hash-index */
310
/* Write a hash-key to the hash-index */
298
312
bool my_hash_insert(HASH *info,const unsigned char *record)
308
322
unsigned char *key= (unsigned char*) hash_key(info, record, &idx, 1);
309
323
if (hash_search(info, key, idx))
310
return(true); /* Duplicate entry */
324
/* Duplicate entry */
314
329
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
315
return(true); /* No more memory */
317
333
data=dynamic_element(&info->array,0,HASH_LINK*);
318
334
halfbuff= info->blength >> 1;
320
336
idx=first_index=info->records-halfbuff;
321
if (idx != info->records) /* If some records */
337
/* If some records */
338
if (idx != info->records)
326
343
hash_nr=rec_hashnr(info,pos->data);
327
if (flag == 0) /* First loop; Check if ok */
328
if (hash_mask(hash_nr,info->blength,info->records) != first_index)
344
/* First loop; Check if ok */
346
if (hash_mask(hash_nr,info->blength,info->records) != first_index)
330
348
if (!(hash_nr & halfbuff))
331
{ /* Key will not move */
332
if (!(flag & LOWFIND))
336
flag=LOWFIND | HIGHFIND;
337
/* key shall be moved to the current empty position */
339
ptr_to_rec=pos->data;
340
empty=pos; /* This place is now free */
344
flag=LOWFIND | LOWUSED; /* key isn't changed */
346
ptr_to_rec=pos->data;
351
if (!(flag & LOWUSED))
353
/* Change link of previous LOW-key */
354
gpos->data=ptr_to_rec;
355
gpos->next= (uint) (pos-data);
356
flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
359
ptr_to_rec=pos->data;
350
/* Key will not move */
351
if (!(flag & LOWFIND))
355
flag=LOWFIND | HIGHFIND;
356
/* key shall be moved to the current empty position */
358
ptr_to_rec=pos->data;
359
/* This place is now free */
364
/* key isn't changed */
365
flag=LOWFIND | LOWUSED;
367
ptr_to_rec=pos->data;
372
if (!(flag & LOWUSED))
374
/* Change link of previous LOW-key */
375
gpos->data=ptr_to_rec;
376
gpos->next= (uint) (pos-data);
377
flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
380
ptr_to_rec=pos->data;
363
{ /* key will be moved */
364
if (!(flag & HIGHFIND))
366
flag= (flag & LOWFIND) | HIGHFIND;
367
/* key shall be moved to the last (empty) position */
368
gpos2 = empty; empty=pos;
369
ptr_to_rec2=pos->data;
373
if (!(flag & HIGHUSED))
375
/* Change link of previous hash-key and save */
376
gpos2->data=ptr_to_rec2;
377
gpos2->next=(uint) (pos-data);
378
flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
381
ptr_to_rec2=pos->data;
385
/* key will be moved */
386
if (!(flag & HIGHFIND))
388
flag= (flag & LOWFIND) | HIGHFIND;
389
/* key shall be moved to the last (empty) position */
390
gpos2 = empty; empty=pos;
391
ptr_to_rec2=pos->data;
395
if (!(flag & HIGHUSED))
397
/* Change link of previous hash-key and save */
398
gpos2->data=ptr_to_rec2;
399
gpos2->next=(uint) (pos-data);
400
flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
403
ptr_to_rec2=pos->data;
385
407
while ((idx=pos->next) != NO_RECORD);
518
Update keys when record has changed.
519
This is much more efficent than using a delete & insert.
545
Update keys when record has changed.
546
This is much more efficent than using a delete & insert.
522
549
bool hash_update(HASH *hash, unsigned char *record, unsigned char *old_key,
523
size_t old_key_length)
550
size_t old_key_length)
525
552
uint32_t new_index,new_pos_index,blength,records,empty;
527
554
HASH_LINK org_link,*data,*previous,*pos;
529
556
if (HASH_UNIQUE & hash->flags)
531
558
HASH_SEARCH_STATE state;
532
unsigned char *found, *new_key= (unsigned char*) hash_key(hash, record, &idx, 1);
559
unsigned char *found,
560
*new_key= (unsigned char*) hash_key(hash, record, &idx, 1);
533
562
if ((found= hash_first(hash, new_key, idx, &state)))
537
566
if (found != record)
538
567
return(1); /* Duplicate entry */
540
569
while ((found= hash_next(hash, new_key, idx, &state)));