00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include <drizzled/my_hash.h>
00026 #include <drizzled/charset.h>
00027 #include <vector>
00028
00029 namespace drizzled {
00030
00031 const uint32_t NO_RECORD= UINT32_MAX;
00032
00033 const int LOWFIND= 1;
00034 const int LOWUSED= 2;
00035 const int HIGHFIND= 4;
00036 const int HIGHUSED= 8;
00037
00038 static uint32_t hash_mask(uint32_t hashnr, uint32_t buffmax, uint32_t maxlength);
00039 static void movelink(HASH_LINK *array, uint32_t pos, uint32_t next_link, uint32_t newlink);
00040 static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key, size_t length);
00041
00042 static uint32_t calc_hash(const HASH *hash, const unsigned char *key, size_t length)
00043 {
00044 uint32_t nr1=1, nr2=4;
00045 hash->charset->coll->hash_sort(hash->charset, key,length, &nr1, &nr2);
00046 return nr1;
00047 }
00048
00049 #define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
00050
00051 void
00052 _hash_init(HASH *hash,uint32_t growth_size, const charset_info_st * const charset,
00053 uint32_t size, size_t key_offset, size_t key_length,
00054 hash_get_key get_key,
00055 hash_free_key free_element, uint32_t flags)
00056 {
00057 hash->records=0;
00058 hash->array.init(sizeof(HASH_LINK), size, growth_size);
00059 hash->key_offset=key_offset;
00060 hash->key_length=key_length;
00061 hash->blength=1;
00062 hash->get_key=get_key;
00063 hash->free=free_element;
00064 hash->flags=flags;
00065 hash->charset=charset;
00066 }
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 static inline void hash_free_elements(HASH *hash)
00081 {
00082 if (hash->free)
00083 {
00084 HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
00085 HASH_LINK *end= data + hash->records;
00086 while (data < end)
00087 (*hash->free)((data++)->data);
00088 }
00089 hash->records=0;
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 void hash_free(HASH *hash)
00104 {
00105 hash_free_elements(hash);
00106 hash->free= 0;
00107 hash->array.free();
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117 static inline char*
00118 hash_key(const HASH *hash, const unsigned char *record, size_t *length,
00119 bool first)
00120 {
00121 if (hash->get_key)
00122 return (char*) (*hash->get_key)(record,length,first);
00123 *length=hash->key_length;
00124 return (char*) record+hash->key_offset;
00125 }
00126
00127
00128
00129 static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength)
00130 {
00131 if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
00132 return (hashnr & ((buffmax >> 1) -1));
00133 }
00134
00135 static uint32_t hash_rec_mask(const HASH *hash, HASH_LINK *pos,
00136 uint32_t buffmax, uint32_t maxlength)
00137 {
00138 size_t length;
00139 unsigned char *key= (unsigned char*) hash_key(hash,pos->data,&length,0);
00140 return hash_mask(calc_hash(hash,key,length),buffmax,maxlength);
00141 }
00142
00143
00144
00145 static
00146 inline
00147 unsigned int rec_hashnr(HASH *hash,const unsigned char *record)
00148 {
00149 size_t length;
00150 unsigned char *key= (unsigned char*) hash_key(hash,record,&length,0);
00151 return calc_hash(hash,key,length);
00152 }
00153
00154
00155 unsigned char* hash_search(const HASH *hash, const unsigned char *key,
00156 size_t length)
00157 {
00158 HASH_SEARCH_STATE state;
00159 return hash_first(hash, key, length, &state);
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169 unsigned char* hash_first(const HASH *hash, const unsigned char *key,
00170 size_t length,
00171 HASH_SEARCH_STATE *current_record)
00172 {
00173 HASH_LINK *pos;
00174 uint32_t flag,idx;
00175
00176 flag=1;
00177 if (hash->records)
00178 {
00179 idx=hash_mask(calc_hash(hash,key,length ? length : hash->key_length),
00180 hash->blength,hash->records);
00181 do
00182 {
00183 pos= dynamic_element(&hash->array,idx,HASH_LINK*);
00184 if (!hashcmp(hash,pos,key,length))
00185 {
00186 *current_record= idx;
00187 return (pos->data);
00188 }
00189 if (flag)
00190 {
00191
00192 flag=0;
00193 if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
00194
00195 break;
00196 }
00197 }
00198 while ((idx=pos->next) != NO_RECORD);
00199 }
00200 *current_record= NO_RECORD;
00201 return 0;
00202 }
00203
00204
00205
00206 static void movelink(HASH_LINK *array, uint32_t find,
00207 uint32_t next_link, uint32_t newlink)
00208 {
00209 HASH_LINK *old_link;
00210 do
00211 {
00212 old_link=array+next_link;
00213 }
00214 while ((next_link=old_link->next) != find);
00215 old_link->next= newlink;
00216 return;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
00239 size_t length)
00240 {
00241 size_t rec_keylength;
00242 unsigned char *rec_key= (unsigned char*) hash_key(hash, pos->data,
00243 &rec_keylength,1);
00244 return ((length && length != rec_keylength) ||
00245 my_strnncoll(hash->charset, rec_key, rec_keylength,
00246 key, rec_keylength));
00247 }
00248
00249
00250
00251
00252 bool my_hash_insert(HASH *info,const unsigned char *record)
00253 {
00254 int flag;
00255 size_t idx;
00256 uint32_t halfbuff,hash_nr,first_index;
00257 unsigned char *ptr_to_rec=NULL,*ptr_to_rec2=NULL;
00258 HASH_LINK *data,*empty,*gpos=NULL,*gpos2=NULL,*pos;
00259
00260 if (HASH_UNIQUE & info->flags)
00261 {
00262 unsigned char *key= (unsigned char*) hash_key(info, record, &idx, 1);
00263 if (hash_search(info, key, idx))
00264
00265 return true;
00266 }
00267
00268 flag=0;
00269 empty=(HASH_LINK*)info->array.alloc();
00270
00271 data=dynamic_element(&info->array,0,HASH_LINK*);
00272 halfbuff= info->blength >> 1;
00273
00274 idx= first_index= info->records-halfbuff;
00275
00276 if (idx != info->records)
00277 {
00278 do
00279 {
00280 pos=data+idx;
00281 hash_nr=rec_hashnr(info,pos->data);
00282
00283 if (flag == 0)
00284 if (hash_mask(hash_nr,info->blength,info->records) != first_index)
00285 break;
00286 if (!(hash_nr & halfbuff))
00287 {
00288
00289 if (!(flag & LOWFIND))
00290 {
00291 if (flag & HIGHFIND)
00292 {
00293 flag=LOWFIND | HIGHFIND;
00294
00295 gpos=empty;
00296 ptr_to_rec=pos->data;
00297
00298 empty=pos;
00299 }
00300 else
00301 {
00302
00303 flag=LOWFIND | LOWUSED;
00304 gpos=pos;
00305 ptr_to_rec=pos->data;
00306 }
00307 }
00308 else
00309 {
00310 if (!(flag & LOWUSED))
00311 {
00312
00313 gpos->data=ptr_to_rec;
00314 gpos->next= (uint32_t) (pos-data);
00315 flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
00316 }
00317 gpos=pos;
00318 ptr_to_rec=pos->data;
00319 }
00320 }
00321 else
00322 {
00323
00324 if (!(flag & HIGHFIND))
00325 {
00326 flag= (flag & LOWFIND) | HIGHFIND;
00327
00328 gpos2 = empty; empty=pos;
00329 ptr_to_rec2=pos->data;
00330 }
00331 else
00332 {
00333 if (!(flag & HIGHUSED))
00334 {
00335
00336 gpos2->data=ptr_to_rec2;
00337 gpos2->next=(uint32_t) (pos-data);
00338 flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
00339 }
00340 gpos2=pos;
00341 ptr_to_rec2=pos->data;
00342 }
00343 }
00344 }
00345 while ((idx=pos->next) != NO_RECORD);
00346
00347 if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
00348 {
00349 gpos->data=ptr_to_rec;
00350 gpos->next=NO_RECORD;
00351 }
00352 if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
00353 {
00354 gpos2->data=ptr_to_rec2;
00355 gpos2->next=NO_RECORD;
00356 }
00357 }
00358
00359
00360 idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
00361 pos=data+idx;
00362 if (pos == empty)
00363 {
00364 pos->data=(unsigned char*) record;
00365 pos->next=NO_RECORD;
00366 }
00367 else
00368 {
00369
00370 empty[0]=pos[0];
00371 gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
00372 if (pos == gpos)
00373 {
00374 pos->data=(unsigned char*) record;
00375 pos->next=(uint32_t) (empty - data);
00376 }
00377 else
00378 {
00379 pos->data=(unsigned char*) record;
00380 pos->next=NO_RECORD;
00381 movelink(data,(uint32_t) (pos-data),(uint32_t) (gpos-data),(uint32_t) (empty-data));
00382 }
00383 }
00384 if (++info->records == info->blength)
00385 info->blength+= info->blength;
00386 return 0;
00387 }
00388
00389 }